<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>m i k e  b r e v o o r t &#187; code</title>
	<atom:link href="http://mike.brevoort.com/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://mike.brevoort.com</link>
	<description>life technology etc</description>
	<lastBuildDate>Wed, 18 Aug 2010 14:50:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Introducing the JQuery Facebook Multi-Friend Selector Plugin</title>
		<link>http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/</link>
		<comments>http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 05:23:41 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=374</guid>
		<description><![CDATA[I created a new jQuery plugging that works with the new Facebook javascript SDK to present a users list of friends and allows them to select the friends they would like to do X with. That &#8220;X&#8221; is up to you; once the user has selected their friends, you call a function on the plugin [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F10%2Fintroducing-the-jquery-facebook-multi-friend-selector-plugin%2F"><br />
				<img class="colorbox-374"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F10%2Fintroducing-the-jquery-facebook-multi-friend-selector-plugin%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>I created a new <a href="http://jquery.com/">jQuery</a> plugging that works with the <a href="http://developers.facebook.com/docs/reference/javascript/">new Facebook javascript SDK</a> to present a users list of friends and allows them to select the friends they would like to do X with. That &#8220;X&#8221; is up to you; once the user has selected their friends, you call a function on the plugin that returns an array of the friends Facebook Ids. A few key points:</p>
<ul>
<li>client-side, no server-side PHP blah blah blah dependencies like some of the other alternative friends selectors</li>
<li>depends on jQuery and the new Facebook Javascript API</li>
<li>only requires several lines of code to drop-in</li>
<li>Apache 2.0 license</li>
<li>Hosted at GitHib: <a href="http://github.com/mbrevoort/jquery-facebook-multi-friend-selector">source</a> and <a href="http://mbrevoort.github.com/jquery-facebook-multi-friend-selector/">demo</a></li>
</ul>

<a href='http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/screen-shot-2010-08-10-at-11-03-19-pm/' title='Screen shot 2010-08-10 at 11.03.19 PM'><img width="150" height="150" src="http://mike.brevoort.com/wp-content/uploads/2010/08/Screen-shot-2010-08-10-at-11.03.19-PM-150x150.png" class="attachment-thumbnail colorbox-374" alt="Screen shot 2010-08-10 at 11.03.19 PM" title="Screen shot 2010-08-10 at 11.03.19 PM" /></a>
<a href='http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/screen-shot-2010-08-10-at-11-03-06-pm/' title='Screen shot 2010-08-10 at 11.03.06 PM'><img width="150" height="150" src="http://mike.brevoort.com/wp-content/uploads/2010/08/Screen-shot-2010-08-10-at-11.03.06-PM-150x150.png" class="attachment-thumbnail colorbox-374" alt="Screen shot 2010-08-10 at 11.03.06 PM" title="Screen shot 2010-08-10 at 11.03.06 PM" /></a>

<blockquote><p><span style="text-decoration: underline;">Quick disclaime</span>r- as of this post, I haven&#8217;t done any testing on Windows or IE, just the latest of Chrome, Safari and Firefox on Mac. There are other features I want to include and probably a bug or two to work through, but for the most part it&#8217;s functional.</p></blockquote>
<ul>
<li>display all of a logged in users friends and lets you select zero to all of them</li>
<li>filter by those already selected</li>
<li>fast filter textbox that filters list quickly as you type</li>
<li>shift-select to select multiple friends at a time</li>
</ul>
<p>To use the plugin, you need to include jQuery, the plugin javascript file, the plugin CSS (which you can change) and the Facebook javascript library</p>
<pre class="brush: xml;">
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;jquery.facebook.multifriend.select.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;jquery.facebook.multifriend.select.css&quot; /&gt;
&lt;script src=&quot;http://connect.facebook.net/en_US/all.js&quot;&gt;&lt;/script&gt;
</pre>
<p>You also need to initialized your app by calling <a href="http://developers.facebook.com/docs/reference/javascript/FB.init">FB.init</a> with your appId and have <a href="http://developers.facebook.com/docs/reference/javascript/FB.login">logged the user in</a>, then you can load the friend selector into a container:</p>
<pre class="brush: jscript;">
$(&quot;#jfmfs-container&quot;).jfmfs();
</pre>
<p>This loads the friend selector into the jfmfs-container (can be whatever you want it to be). It calls the F<a href="http://developers.facebook.com/docs/api">acebook Graph API</a> to fetch the list of friends of the logged in user and loads them into the scrollable region. Then after the user has selected their friends, you can call getSelectedIds() on the plugin to get an array of friends Ids that were selected.</p>
<pre class="brush: jscript;">
var friendSelector = $(&quot;#jfmfs-container&quot;).data('jfmfs');
var friendIds = friendSelector.getSelectedIds();
</pre>
<p>A handle to the object is stored as data of the element, so you need to call data(&#8216;jfmfs&#8217;) on the element you loaded the selector to get a handle to the plugin object to call getSelectedIds().</p>
<p>Here&#8217;s a screencast demo. Let me know what you think!</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="575" height="446" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=14052007&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed type="application/x-shockwave-flash" width="575" height="446" src="http://vimeo.com/moogaloop.swf?clip_id=14052007&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><a href="http://vimeo.com/14052007">JQuery Facebook Multi-Friend Selector Plugin Demo</a> from <a href="http://vimeo.com/user229324">mbrevoort</a> on <a href="http://vimeo.com">Vimeo</a>.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/&amp;t=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin+-+http://bit.ly/cHDkzm+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/&amp;title=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin&amp;summary=I%20created%20a%20new%20jQuery%20plugging%20that%20works%20with%20the%20new%20Facebook%20javascript%20SDK%20to%20present%20a%20users%20list%20of%20friends%20and%20allows%20them%20to%20select%20the%20friends%20they%20would%20like%20to%20do%20X%20with.%20That%20%22X%22%20is%20up%20to%20you%3B%20once%20the%20user%20has%20selected%20their%20friends%2C%20you%20call%20a%20function%20on%20the%20plugin%20that%20returns%20an%20ar&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin&amp;link=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/&amp;title=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/&amp;submitHeadline=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin&amp;submitSummary=I%20created%20a%20new%20jQuery%20plugging%20that%20works%20with%20the%20new%20Facebook%20javascript%20SDK%20to%20present%20a%20users%20list%20of%20friends%20and%20allows%20them%20to%20select%20the%20friends%20they%20would%20like%20to%20do%20X%20with.%20That%20%22X%22%20is%20up%20to%20you%3B%20once%20the%20user%20has%20selected%20their%20friends%2C%20you%20call%20a%20function%20on%20the%20plugin%20that%20returns%20an%20ar&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/&amp;title=Introducing+the+JQuery+Facebook+Multi-Friend+Selector+Plugin" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Introducing%20the%20JQuery%20Facebook%20Multi-Friend%20Selector%20Plugin%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%20created%20a%20new%20jQuery%20plugging%20that%20works%20with%20the%20new%20Facebook%20javascript%20SDK%20to%20present%20a%20users%20list%20of%20friends%20and%20allows%20them%20to%20select%20the%20friends%20they%20would%20like%20to%20do%20X%20with.%20That%20%22X%22%20is%20up%20to%20you%3B%20once%20the%20user%20has%20selected%20their%20friends%2C%20you%20call%20a%20function%20on%20the%20plugin%20that%20returns%20an%20ar%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2010/08/10/introducing-the-jquery-facebook-multi-friend-selector-plugin/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>MarkLogic Demos</title>
		<link>http://mike.brevoort.com/2010/08/03/marklogic-demos/</link>
		<comments>http://mike.brevoort.com/2010/08/03/marklogic-demos/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 20:59:38 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[demo]]></category>
		<category><![CDATA[MarkLogic]]></category>
		<category><![CDATA[xquery]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=325</guid>
		<description><![CDATA[Over the last three or four months I&#8217;ve taken a deep dive into MarkLogic, ramping up faster and then working on several interesting projects. Along the way I built a demo for the 2010 MarkLogic Users Conference Demojam (totally last minute over the course of several days), and I won! It&#8217;s was a real time twitter [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F03%2Fmarklogic-demos%2F"><br />
				<img class="colorbox-325"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F03%2Fmarklogic-demos%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>
<img class="alignright size-full wp-image-327 colorbox-325" title="Winning Demojam" src="http://mike.brevoort.com/wp-content/uploads/2010/08/UC-2010-brevoort-winning-dem-ojam-1.jpg" alt="" width="240" height="160" style="float:right;"/><br />
Over the last three or four months I&#8217;ve taken a deep dive into MarkLogic, ramping up faster and then working on several interesting projects. Along the way I built a demo for the 2010 MarkLogic Users Conference Demojam (totally last minute over the course of several days), and I won! It&#8217;s was a real time twitter search and workflow system with geospatial capabilities. Afterwards, I recorded this screencast overview of what I built.
</p>
<p><object width="550" height="364"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=11559515&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=11559515&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="550" height="364"></embed></object><br />
<br />
I also found a demo I recorded after my 1st week of tinkering with MarkLogic. This is a simple demonstration of the read/write capabilities and benefits of XML being both ordered and hierarchical. The demo uses jQuery to wire together some ajax calls to reorder lists of items.</p>
<p><object width="550" height="426"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=10910025&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=10910025&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="550" height="426"></embed></object></p>
<p>I feel like I&#8217;m cleaning out the closet&#8230;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2010/08/03/marklogic-demos/&amp;t=MarkLogic+Demos" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=MarkLogic+Demos+-+http://bit.ly/bcJ4S2+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2010/08/03/marklogic-demos/&amp;title=MarkLogic+Demos&amp;summary=%0D%0A%0D%0AOver%20the%20last%20three%20or%20four%20months%20I%27ve%20taken%20a%20deep%20dive%20into%20MarkLogic%2C%20ramping%20up%20faster%20and%20then%20working%20on%20several%20interesting%20projects.%20Along%20the%20way%20I%20built%20a%20demo%20for%20the%202010%20MarkLogic%20Users%20Conference%20Demojam%20%28totally%20last%20minute%20over%20the%20course%20of%20several%20days%29%2C%20and%20I%20won%21%C2%A0It%27s%20was%20a&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=MarkLogic+Demos&amp;link=http://mike.brevoort.com/2010/08/03/marklogic-demos/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2010/08/03/marklogic-demos/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2010/08/03/marklogic-demos/&amp;title=MarkLogic+Demos" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2010/08/03/marklogic-demos/&amp;submitHeadline=MarkLogic+Demos&amp;submitSummary=%0D%0A%0D%0AOver%20the%20last%20three%20or%20four%20months%20I%27ve%20taken%20a%20deep%20dive%20into%20MarkLogic%2C%20ramping%20up%20faster%20and%20then%20working%20on%20several%20interesting%20projects.%20Along%20the%20way%20I%20built%20a%20demo%20for%20the%202010%20MarkLogic%20Users%20Conference%20Demojam%20%28totally%20last%20minute%20over%20the%20course%20of%20several%20days%29%2C%20and%20I%20won%21%C2%A0It%27s%20was%20a&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2010/08/03/marklogic-demos/&amp;title=MarkLogic+Demos" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22MarkLogic%20Demos%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22%0D%0A%0D%0AOver%20the%20last%20three%20or%20four%20months%20I%27ve%20taken%20a%20deep%20dive%20into%20MarkLogic%2C%20ramping%20up%20faster%20and%20then%20working%20on%20several%20interesting%20projects.%20Along%20the%20way%20I%20built%20a%20demo%20for%20the%202010%20MarkLogic%20Users%20Conference%20Demojam%20%28totally%20last%20minute%20over%20the%20course%20of%20several%20days%29%2C%20and%20I%20won%21%C2%A0It%27s%20was%20a%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2010/08/03/marklogic-demos/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2010/08/03/marklogic-demos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gluing Confluence Activity to Socialcast with Google App Engine / Gaelyk</title>
		<link>http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/</link>
		<comments>http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 23:42:26 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[activity streams]]></category>
		<category><![CDATA[confluence]]></category>
		<category><![CDATA[gaelyk]]></category>
		<category><![CDATA[google app engine]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[socialcast]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=289</guid>
		<description><![CDATA[I&#8217;ve been experimenting with ways to tie the activity of some of the systems we use together. In this case I would like activity information from Confluence to be streamed into Socialcast. There are several ways to go about this but none are perfect or &#8220;out of the box&#8221;. Before I go on, here&#8217;s what [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F02%2Fgluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk%2F"><br />
				<img class="colorbox-289"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2010%2F08%2F02%2Fgluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>I&#8217;ve been experimenting with ways to tie the activity of some of the systems we use together.  In this case I would like activity information from <a href="http://www.atlassian.com/software/confluence/">Confluence</a> to be streamed into <a href="http://socialcast.com">Socialcast</a>. There are several ways to go about this but none are perfect or &#8220;out of the box&#8221;.</p>
<p>Before I go on, here&#8217;s what this looks like in Socialcast with the verb and actor mentioned and object name and link:</p>
<p><a href="http://mike.brevoort.com/wp-content/uploads/2010/08/Screen-shot-2010-08-02-at-5.15.27-PM1.png"><img class="aligncenter size-full wp-image-322 colorbox-289" title="Screen shot 2010-08-02 at 5.15.27 PM" src="http://mike.brevoort.com/wp-content/uploads/2010/08/Screen-shot-2010-08-02-at-5.15.27-PM1.png" alt="" width="550" height="103" /></a></p>
<h2>A Little Background</h2>
<p>You could configure a stream import in Socialcast with an RSS feed from Confluence though there are two problems with this. First, Confluence requires authentication and doesn&#8217;t support any token type convention so you have to hardcode the username and password of an account that has access to the activity you&#8217;re interested in in Confluence. Second, Socialcast appears to truncate long URLs for RSS feeds (consider this a reported bug <img src='http://mike.brevoort.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley colorbox-289' /> ). So the only way I got this to work was to use a URL shortener like bit.ly but a Confluence username and password was hardcoded at bit.ly and the bit.ly URL was used in the RSS feed import. And finally what was imported wasn&#8217;t linkable back to Confluence. So there were many stumbling blocks in this, though the simplest approach.</p>
<p>Second I created a confluence-bot user account in both Confluence and Socialcast (with the account in Socialcast having the email address that Confluence would send from) and set this account as a watcher to all of the spaces I wanted activity information to be published. Then I created a group in Socialcast where activity would be published. The email address of the confluence-bot account was set to the email address of the Socialcast group. So when Confluence sent the watch emails out for confluence-bot, they would be sent to the Socialcast group. For some reason this just didn&#8217;t work; the emails were never arriving. I suspect Socialcast was filtering the emails as spam, as they contained a &#8216;<em>Precedence: bulk&#8217;</em> header. It was worth a try but much too kludgy without any control so not worth pursuing in my opinion.</p>
<p>Ideally I wish Confluence had more dynamic notification options. More specifically I wish I could register a <a href="http://wiki.webhooks.org/">webhook</a> in confluence that would let me process watch events or notifications. Even cooler would be to let each user configure a webhook URL. This would decouple the notification from the event and eliminate the need to write a Confluence plugin to handle something like this. For example, if I wanted to get Growl notifications on my desktop for Confluence activity, I could configure a webhook to post to <a href="http://progrium.com/">Jeff Lindsay&#8217;s</a> <a href="http://notify.io">Noftify.io</a> service (awesome by the way!).</p>
<p>Anyway, in lieu of that, I decided to hack together watcher emails from Confluence to Socialcast using <a href="http://gaelyk.appspot.com/">Gaelyk</a> on <a href="http://code.google.com/appengine/">Google App Engine</a> and the Socialcast API.</p>
<h2>Confluence -&gt; GAE -&gt; Socialcast</h2>
<p><a href="http://mike.brevoort.com/wp-content/uploads/2010/08/Confluence_Socialcast_Glue_Diagram.001.png"><img class="size-full wp-image-291 colorbox-289" style="text-align: center; clear: both;" title="Confluence_Socialcast_Glue_Diagram.001" src="http://mike.brevoort.com/wp-content/uploads/2010/08/Confluence_Socialcast_Glue_Diagram.001.png" alt="" width="550" /></a></p>
<h3>Using Gaelyk and Google App Engine as the Glue</h3>
<p>Confluence can send out email notifications based on watched content, and Google App Engine applications can act as an SMTP endpoint so since I&#8217;m a Groovy fan and been looking for an excuse to kick the tires on Gaelyk, I created a very simple Gaelyk application with an email handler that parsed incoming messages from Confluence and called the RESTful Socialcast API to create new messages. Unfortunately the HTML email Confluence produces isn&#8217;t valid xhtml, with unclosed tags and such, so I can&#8217;t just parse the XML and pull out the bits I need. I used some quick and dirty regular expressions to grab what I needed, making assumptions that the format of the emails wouldn&#8217;t change. I suppose I could fix the Confluence email templates, but I&#8217;m trying not to touch Confluence programmatically in this case. He&#8217;s a stripped down version of the email handler (<strong>&lt;my_project&gt;/war/WEB-INF/groovy/email.groovy</strong>):</p>
<pre class="brush: groovy;">
// have access to message object of javax.mail.internet.MimeMessage
import groovyx.gaelyk.logging.GroovyLogger
import java.io.BufferedReader;
import java.io.OutputStreamWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.HttpURLConnection;

def log = new GroovyLogger(&quot;emailLogger&quot;)

// the email notification message from confluence is a bit messy, try to pull out the important bits from it
def theLink = &quot;&quot;
def m1 = message.content =~ /&lt;\/?(?i:a)(.|\n)*?&gt;/
if(m1?.size() &gt; 0) {
    def firstAnchor = m1[0][0]
    def m2 = firstAnchor =~  /href=&quot;(.)*&quot;/
    if(m2?.size() &gt; 0) {
        theLink = m2[0][0] - &quot;href=\&quot;&quot; - &quot;\&quot;&quot;
    }
}

String content = message.content;
int start = content.indexOf(&quot;&lt;h4&gt;&quot;) + 4;
int end = content.indexOf(&quot;&lt;/h4&gt;&quot;);
def details = content.substring(start, end).replaceAll(/&lt;\/?(?i:a|b)(.|\n)*?&gt;/, '')

def user = &quot;confluence-bot@mydomain.com&quot;;
def pass = &quot;mypassword&quot;;
def addr = &quot;https://mydomain.socialcast.com/api/messages.xml&quot;

def authString = &quot;${user}:${pass}&quot;.getBytes().encodeBase64().toString()
def conn = addr.toURL().openConnection()
conn.setRequestProperty(&quot;Authorization&quot;, &quot;Basic ${authString}&quot;)
conn.setRequestMethod(&quot;POST&quot;)
conn.doOutput = true

def queryString = &quot;message[title]=${URLEncoder.encode(message.subject)}&amp;&quot; + &quot;message[body]=${URLEncoder.encode(details)}&quot; + &quot;&amp;message[url]=${URLEncoder.encode(theLink)}&quot; + &quot;&amp;message[group_id]=6845&quot;;

def writer = new OutputStreamWriter(conn.outputStream)
writer.write(queryString)
writer.flush()
writer.close()
conn.connect()

def res = conn.content.text
log.info(res)
</pre>
<p>There&#8217;s some configuration required to turn on the inbound email service and map the incoming email to the proper Groovlet.</p>
<p>Add this to your <strong>appengine-web.xml</strong>:</p>
<pre class="brush: xml;">
&lt;inbound-services&gt;
    &lt;service&gt;mail&lt;/service&gt;
&lt;/inbound-services&gt;
</pre>
<p>In your <strong>web.xml</strong> file, add the new servlet mapping and security constraint:</p>
<pre class="brush: xml;">
...
&lt;servlet&gt;
    &lt;servlet-name&gt;EmailServlet&lt;/servlet-name&gt;
    &lt;servlet-class&gt;groovyx.gaelyk.GaelykIncomingEmailServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;
...
&lt;servlet-mapping&gt;
    &lt;servlet-name&gt;EmailServlet&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/_ah/mail/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
...
&lt;!-- Only allow the SDK and administrators to have access to the incoming email endpoint --&gt;
&lt;security-constraint&gt;
    &lt;web-resource-collection&gt;
        &lt;url-pattern&gt;/_ah/mail/*&lt;/url-pattern&gt;
    &lt;/web-resource-collection&gt;
    &lt;auth-constraint&gt;
        &lt;role-name&gt;admin&lt;/role-name&gt;
    &lt;/auth-constraint&gt;
&lt;/security-constraint&gt;
...
</pre>
<p>There are obvious improvements that can be made to this approach and much better ways to go about this, along with a lot of considerations that I ignored (e.g. security/permissions) but for a few hours of hacking this is hard to beat!</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/&amp;t=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk+-+http://bit.ly/cYRP6v+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/&amp;title=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk&amp;summary=I%27ve%20been%20experimenting%20with%20ways%20to%20tie%20the%20activity%20of%20some%20of%20the%20systems%20we%20use%20together.%20%20In%20this%20case%20I%20would%20like%20activity%20information%20from%20Confluence%20to%20be%20streamed%20into%20Socialcast.%20There%20are%20several%20ways%20to%20go%20about%20this%20but%20none%20are%20perfect%20or%20%22out%20of%20the%20box%22.%0D%0A%0D%0ABefore%20I%20go%20on%2C%20here%27s%20wh&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk&amp;link=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/&amp;title=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/&amp;submitHeadline=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk&amp;submitSummary=I%27ve%20been%20experimenting%20with%20ways%20to%20tie%20the%20activity%20of%20some%20of%20the%20systems%20we%20use%20together.%20%20In%20this%20case%20I%20would%20like%20activity%20information%20from%20Confluence%20to%20be%20streamed%20into%20Socialcast.%20There%20are%20several%20ways%20to%20go%20about%20this%20but%20none%20are%20perfect%20or%20%22out%20of%20the%20box%22.%0D%0A%0D%0ABefore%20I%20go%20on%2C%20here%27s%20wh&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/&amp;title=Gluing+Confluence+Activity+to+Socialcast+with+Google+App+Engine+%2F+Gaelyk" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Gluing%20Confluence%20Activity%20to%20Socialcast%20with%20Google%20App%20Engine%20%2F%20Gaelyk%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%27ve%20been%20experimenting%20with%20ways%20to%20tie%20the%20activity%20of%20some%20of%20the%20systems%20we%20use%20together.%20%20In%20this%20case%20I%20would%20like%20activity%20information%20from%20Confluence%20to%20be%20streamed%20into%20Socialcast.%20There%20are%20several%20ways%20to%20go%20about%20this%20but%20none%20are%20perfect%20or%20%22out%20of%20the%20box%22.%0D%0A%0D%0ABefore%20I%20go%20on%2C%20here%27s%20wh%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2010/08/02/gluing-confluence-activity-to-socialcast-with-google-app-engine-gaelyk/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Making Relative URLs Absolute with Groovy</title>
		<link>http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/</link>
		<comments>http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/#comments</comments>
		<pubDate>Sun, 21 Dec 2008 22:47:11 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=165</guid>
		<description><![CDATA[I’m working on a project where I am using Grails as a content delivery layer for an XML based content management system.  The content management system has the ability to publish XHTML content with inline links and images; however the inline img and a tags reference the content as relative paths.  I need the links [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F12%2F21%2Fmaking-relative-urls-absolute-with-groovy%2F"><br />
				<img class="colorbox-165"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F12%2F21%2Fmaking-relative-urls-absolute-with-groovy%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>I’m working on a project where I am using <a href="http://grails.org">Grails</a> as a content delivery layer for an XML based content management system.  The content management system has the ability to publish XHTML content with inline links and images; however the inline img and a tags reference the content as relative paths.  I need the links to internal pages to be absolute from the server root (ie /sub/content.html rather than sub/content.html) and I am hosting all static content like images at <a href="http://aws.amazon.com/s3/">Amazon S3</a> so I need the image links to be absolute to a different DNS name (ie http://media.mywebsite.com/images/image.jpg rather than images/image.jpg).
</p>
<p>Instead of implementing some hacks in the CMS itself, I opted to do the transformation in Grails as the content was rendered allowing greater flexibility.  I created a taglib for rendering the XHTML block that does a <a href="http://groovy.codehaus.org/Regular+Expressions">Groovy replaceAll with regular expressions</a>.  The tag gets called like this: &lt;g:processXHTML content=&#8221;${content.mainBody.text()}&#8221;/&gt; .  My <a href="http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.2%20Groovy%20Server%20Pages">GSP</a> has reference to a content variable that is an <a href="http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlSlurper">XMLSlurped</a> xml document with a mainBody tag.  Here is the code for the tag:
</p>
<pre class="brush: java;">
/**
 * Given XHTML content will return the same content with any relative a tag hrefs prefixed with a /
 * and any relative images prefixed with the mediaURL
 */

def processIngeniuxXHTML = {attrs -&gt;
  def content = attrs.content
  def rootURL = grailsApplication.config.mediaURL

  if (content) {
    // first look for links within the content that are relative URLS and prefix with a slash so they are
    // resolved from the root rather than the current context
    def regex = /(&lt; \s*a\s+[^&gt;]*href\s*=\s*[\&quot;'])(?!http)([^\&quot;'&gt;]+)[\&quot;'&gt;]/
    def replace = { fullMatch, a, b -&gt;
      if (b[0] != &quot;/&quot;){
        // for some reason it's not outputing the closing quote so I added it at then end explicitly
        &quot;${a}/${b}\&quot;&quot;
      } else
        &quot;${fullMatch}&quot;
    }

    content = content.replaceAll(regex, replace)

    // second if there are any images referenced with relative URLs, prefix with the DNS for the S3 bucket
    regex = /(&lt; \s*img\s+[^&gt;]*src\s*=\s*[\&quot;'])(?!http)([^\&quot;'&gt;]+)[\&quot;'&gt;]/
    replace = { fullMatch, a, b -&gt;
      if (b[0] != &quot;/&quot;){
        // for some reason it's not outputing the closing quote so I added it at then end explicitly
        &quot;${a}${rootURL}/${b}\&quot;&quot;
      } else
        &quot;${fullMatch}&quot;
    }

    out &lt; &lt; content.replaceAll(regex, replace)
  }
}
</pre>
<p>And here are the test conditions to demonstrate what&#8217;s expected:</p>
<pre class="brush: java;">
void testProcessXHTML() {
  ContentUtilTagLib tl = new ContentUtilTagLib()

  def i = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;Explore/test&quot;/&gt;&quot;&quot;&quot;
  def o = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;/Explore/test&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;

  tl.processXHTML(content: i)
  assertEquals o, out.toString()
  out.getBuffer().setLength(0)

  i = &quot;&quot;&quot;&lt;div&gt;&lt;a alt=&quot;blah&quot; href=&quot;Explore/test&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;
  o = &quot;&quot;&quot;&lt;div&gt;&lt;a alt=&quot;blah&quot; href=&quot;/Explore/test&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;

  tl.processXHTML(content: i)
  assertEquals o, out.toString()
  out.getBuffer().setLength(0)

  i = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;Explore/test&quot;/&gt;&lt;img width=&quot;100&quot; src=&quot;myImage/a.jpg&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;
  o = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;/Explore/test&quot;/&gt;&lt;img width=&quot;100&quot; src=&quot;http://stub/myImage/a.jpg&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;

  tl.processXHTML(content: i)
  assertEquals o, out.toString()
  out.getBuffer().setLength(0)

  i = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;/Explore/test&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;
  o = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;/Explore/test&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;

  tl.processXHTML(content: i)
  assertEquals o, out.toString()
  out.getBuffer().setLength(0)

  i = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;http://Explore/test&quot;/&gt;&lt;img width=&quot;100&quot; src=&quot;http://anotherhost/myImage/a.jpg&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;
  o = &quot;&quot;&quot;&lt;div&gt;&lt;a href=&quot;http://Explore/test&quot;/&gt;&lt;img width=&quot;100&quot; src=&quot;http://anotherhost/myImage/a.jpg&quot;/&gt;&lt;/div&gt;&quot;&quot;&quot;

  tl.processXHTML(content: i)
  assertEquals o, out.toString()
  out.getBuffer().setLength(0)

}
</pre>
<p>More related to this project to come&#8230;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/&amp;t=Making+Relative+URLs+Absolute+with+Groovy" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Making+Relative+URLs+Absolute+with+Groovy+-+http://bit.ly/32ip32+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/&amp;title=Making+Relative+URLs+Absolute+with+Groovy&amp;summary=I%E2%80%99m%20working%20on%20a%20project%20where%20I%20am%20using%20Grails%20as%20a%20content%20delivery%20layer%20for%20an%20XML%20based%20content%20management%20system.%C2%A0%20The%20content%20management%20system%20has%20the%20ability%20to%20publish%20XHTML%20content%20with%20inline%20links%20and%20images%3B%20however%20the%20inline%20img%20and%20a%20tags%20reference%20the%20content%20as%20relative%20paths.&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Making+Relative+URLs+Absolute+with+Groovy&amp;link=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/&amp;title=Making+Relative+URLs+Absolute+with+Groovy" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/&amp;submitHeadline=Making+Relative+URLs+Absolute+with+Groovy&amp;submitSummary=I%E2%80%99m%20working%20on%20a%20project%20where%20I%20am%20using%20Grails%20as%20a%20content%20delivery%20layer%20for%20an%20XML%20based%20content%20management%20system.%C2%A0%20The%20content%20management%20system%20has%20the%20ability%20to%20publish%20XHTML%20content%20with%20inline%20links%20and%20images%3B%20however%20the%20inline%20img%20and%20a%20tags%20reference%20the%20content%20as%20relative%20paths.&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/&amp;title=Making+Relative+URLs+Absolute+with+Groovy" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Making%20Relative%20URLs%20Absolute%20with%20Groovy%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%E2%80%99m%20working%20on%20a%20project%20where%20I%20am%20using%20Grails%20as%20a%20content%20delivery%20layer%20for%20an%20XML%20based%20content%20management%20system.%C2%A0%20The%20content%20management%20system%20has%20the%20ability%20to%20publish%20XHTML%20content%20with%20inline%20links%20and%20images%3B%20however%20the%20inline%20img%20and%20a%20tags%20reference%20the%20content%20as%20relative%20paths.%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/12/21/making-relative-urls-absolute-with-groovy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Active Directory Authentication Part II</title>
		<link>http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/</link>
		<comments>http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/#comments</comments>
		<pubDate>Sat, 27 Sep 2008 06:19:01 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[LDAP]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=113</guid>
		<description><![CDATA[This is a long overdue follow-up to my Active Directory Authentication post. I had all the best intentions of quickly following this post up with a second post so this is long overdue. It&#8217;s been just over a year though so there are lots of cobwebs so this is going to be a stream of [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F09%2F27%2Factive-directory-authentication-part-ii%2F"><br />
				<img class="colorbox-113"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F09%2F27%2Factive-directory-authentication-part-ii%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>This is a long overdue follow-up to my <a href="http://mike.brevoort.com/2007/09/25/active-directory-authentication/">Active Directory Authentication</a> post.  I had all the best intentions of quickly following this post up with a second post so this is long overdue.  It&#8217;s been just over a year though so there are lots of cobwebs so this is going to be a stream of consciousness dump&#8230;</p>
<p>First, there are two books that I found indespensible and the best resources I could find for detailed information about integrating with Active Directory and Windows security.  The LogonUser and SSPI approach I mentioned in my first post a year ago originated from these books.</p>
<ul>
<li><a href="http://www.amazon.com/Developers-Directory-Programming-Microsoft-Development/dp/0321350170/ref=pd_bxgy_b_text_b">The .NET Developer&#8217;s Guide to Directory Services Programming</a></li>
<li><a href="http://www.amazon.com/Developers-Windows-Security-Microsoft-Development/dp/0321228359/ref=pd_bbs_sr_3?ie=UTF8&#038;s=books&#038;qid=1222493272&#038;sr=8-3">The .NET Developer&#8217;s Guide to Windows Security</a></li>
</ul>
<p>In an effort to just get some follow-up out there since I tend to get regular inquiries about my original post, Here&#8217;s a <a href="http://mike.brevoort.com/wp-content/uploads/2008/09/adauthfiles.zip">zip file of some sanitized code</a> that includes the code for LogonUser, SSPI and a few other classes I used.<br />
In the end I settled on LogonUser which seemed to give the best overall performance in a very decentralized, many sub-domain environment.  There were also less anomalies as well.  When using SSPI I found that if typical authentication took 140ms, some calls were taking 60.140s and 120.140s in one or two domains.  This was rare and most likely a result of some sort of timeout and retry or fallback to another domain controller.  I was not able to identify the root cause. </p>
<p>One side note regarding the LogonUse API.  When the authentication type is set to &#8220;LOGON32 LOGON NETWORK&#8221; the LastLogon and LastLogonTimeStamp attributes on the domain controllers are not updated when authentication occurs.   If you have any logic that relies on these attributes (For example if you to run a script against AD to check for user account inactivity), change the authentication type to &#8220;LOGON32 LOGON INTERACTIVE&#8221; to have these attributes updated as expected.</p>
<p>Lastly to test the differences between the three authentication types, I created a method to log detailed information about each authentication attempt including: elapsed time, samAccountName, domain, authentication result, user ip, domain server authenticated against (if I could figure it out), authentication web server.  Without going into too much detail, I logged this info into a row in a database table on each attempt (this also inherently created a great resource for security auditing).  This way I could query the data very easily to roll-up statistics based on which domain, what server, the IP subnet of the user, particular users, etc.  Key to this though was to avoid any additional latency on the authentication request or a database dependency on the success of the authentication request, I created a BlockingQueue that waited for a log message to be placed on the queue and inserted it into the database.  This happened out of band in another thread and if there was some failure, the queue would just continue to grow until the problem was resolved.  This was very effective in measuring the performance of these different authentication methods.</p>
<p>Feel free to comment with any questions, I&#8217;ll do my best to recollect.  </p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/&amp;t=Active+Directory+Authentication+Part+II" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Active+Directory+Authentication+Part+II+-+http://bit.ly/4qmzMM+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/&amp;title=Active+Directory+Authentication+Part+II&amp;summary=This%20is%20a%20long%20overdue%20follow-up%20to%20my%20Active%20Directory%20Authentication%20post.%20%20I%20had%20all%20the%20best%20intentions%20of%20quickly%20following%20this%20post%20up%20with%20a%20second%20post%20so%20this%20is%20long%20overdue.%20%20It%27s%20been%20just%20over%20a%20year%20though%20so%20there%20are%20lots%20of%20cobwebs%20so%20this%20is%20going%20to%20be%20a%20stream%20of%20consciousness%20d&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Active+Directory+Authentication+Part+II&amp;link=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/&amp;title=Active+Directory+Authentication+Part+II" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/&amp;submitHeadline=Active+Directory+Authentication+Part+II&amp;submitSummary=This%20is%20a%20long%20overdue%20follow-up%20to%20my%20Active%20Directory%20Authentication%20post.%20%20I%20had%20all%20the%20best%20intentions%20of%20quickly%20following%20this%20post%20up%20with%20a%20second%20post%20so%20this%20is%20long%20overdue.%20%20It%27s%20been%20just%20over%20a%20year%20though%20so%20there%20are%20lots%20of%20cobwebs%20so%20this%20is%20going%20to%20be%20a%20stream%20of%20consciousness%20d&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/&amp;title=Active+Directory+Authentication+Part+II" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Active%20Directory%20Authentication%20Part%20II%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22This%20is%20a%20long%20overdue%20follow-up%20to%20my%20Active%20Directory%20Authentication%20post.%20%20I%20had%20all%20the%20best%20intentions%20of%20quickly%20following%20this%20post%20up%20with%20a%20second%20post%20so%20this%20is%20long%20overdue.%20%20It%27s%20been%20just%20over%20a%20year%20though%20so%20there%20are%20lots%20of%20cobwebs%20so%20this%20is%20going%20to%20be%20a%20stream%20of%20consciousness%20d%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Expanding on Jira&#8217;s LDAP Integration</title>
		<link>http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/</link>
		<comments>http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/#comments</comments>
		<pubDate>Tue, 08 Apr 2008 22:23:32 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[Jira]]></category>
		<category><![CDATA[LDAP]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/?p=123</guid>
		<description><![CDATA[I recently had the opportunity to do a fresh installation of Atlassian Jira and was faced again with how to integrate Jira with LDAP (in this case Active Directory). Jira does support simple authentication integration with LDAP via OSUser but requires that each LDAP user exist in Jira first. So if an LDAP user needs [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F04%2F08%2Fsyncing-jira-with-ldap%2F"><br />
				<img class="colorbox-123"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F04%2F08%2Fsyncing-jira-with-ldap%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>I recently had the opportunity to do a fresh installation of <a href="http://www.atlassian.com">Atlassian</a> <a href="http://www.atlassian.com/software/jira/">Jira</a> and was faced again with how to integrate Jira with LDAP (in this case Active Directory).  Jira does support <a href="http://www.atlassian.com/software/jira/docs/latest/ldap.html">simple authentication integration</a> with LDAP via <a href="http://www.opensymphony.com/osuser/">OSUser</a> but requires that each LDAP user exist in Jira first.  So if an LDAP user needs access to Jira, I have to go to Jira and create a new corresponding user record with the same user id as LDAP (sAMAccountName in this case).  Ideally I would like Jira to synchronize LDAP users based on some query filter.</p>
<p>Luckily Jira has a perfect way to address this &#8220;opportunity&#8221;: <a href="http://www.atlassian.com/software/jira/docs/latest/services.html">Services</a>.  Jira Services are asynchronous scheduled units of work configured to run within Jira.  I created a new service using JNDI called LDAPUserSyncService that can periodically query LDAP user objects based on configurable filter and create new Jira users for new users it finds in LDAP.  I also added the ability to put a subset of users in a group called &#8220;internal-users&#8221; for users whose email matched a particular domain.</p>
<p>Its pretty simple.  When the service runs, it queries LDAP, iterates through each user checking if the user already exists in LDAP, if not it created the user and puts it in the jira-users group and then checks if the email address contains myco.com (fictitious domain for this example) and if so put the user in the internal group as well.  I just realized as I&#8217;m writing this though that I didn&#8217;t do anything to handle paging or results if the number of users is greater than the max returned by LDAP.  Oh well, maybe another time&#8230;</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
public class LDAPUserSyncService extends AbstractService {

    private static org.apache.log4j.Category log =
            org.apache.log4j.Category.getInstance(LDAPUserSyncService.class);

    public static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
    public static String GROUP_INTERNAL =  "Internal-Users";
    public static String LDAP_USER_ID_ATTRIBUTE = "sAMAccountName";

    public void run() {
        try {
            log.debug("Running com.myco.jira.service.LDAPUserSyncService");
            String LDAP_HOST = getProperty("LDAP_HOST");
            String LDAP_USER = getProperty("LDAP_USER");
            String LDAP_PASSWORD = getProperty("LDAP_PASSWORD");
            String LDAP_SEARCHBASE = getProperty("LDAP_SEARCHBASE");
            String LDAP_FILTER = getProperty("LDAP_FILTER");   

            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);
            env.put(Context.PROVIDER_URL, LDAP_HOST);
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            env.put(Context.SECURITY_PRINCIPAL, LDAP_USER);
            env.put(Context.SECURITY_CREDENTIALS, LDAP_PASSWORD);

            DirContext ctx = new InitialDirContext(env);

            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

            NamingEnumeration results = ctx.search(LDAP_SEARCHBASE, LDAP_FILTER, constraints);

            while(results != null &#038;&#038; results.hasMore()) {
                SearchResult sr = (SearchResult) results.next();
                Attributes attrs = sr.getAttributes();
                log.debug("Processing " + attrs.get("dn"));

                // need sn, givenName, mail
                String first = (attrs.get("givenName") != null) ? (String) attrs.get("givenName").get() : null;
                String last = (attrs.get("sn") != null) ? (String) attrs.get("sn").get() : null;
                String mail = (attrs.get("mail") != null) ? (String) attrs.get("mail").get() : null;
                String userId = (attrs.get(LDAP_USER_ID_ATTRIBUTE) != null) ? (String) attrs.get(LDAP_USER_ID_ATTRIBUTE).get() : null;

                if(first != null &#038;&#038; last != null &#038;&#038; mail != null &#038;&#038; userId != null) {

                    // check if user is in Jira
                    if(!userExists(userId.toLowerCase())) {

                        // create user, if a myco company user then add to internal group
                        if(createJiraUser(userId, first, last, mail) != null) {
                            if(mail.contains("myco.com"))
                                addUserGroup(userId, GROUP_INTERNAL);
                        } else {
                            log.error("LDAP User " + userId + " could not be created");
                        }
                    }
                }
            }
        } catch (NamingException nex) {
            log.error("Caught exception trying to Synch LDAP Users: " + nex.toString());
        } catch (ObjectConfigurationException oce) {
            log.error("Caught exception trying to Synch LDAP Users.  Configuration setup failed: " + oce.toString());
        }
    }

    private User createJiraUser(String userId, String fname, String lname, String email) {

        UserManager userMgr = UserManager.getInstance();
        User osUser = null;
        try {
            osUser = userMgr.createUser(userId.toLowerCase());
            osUser.setFullName(fname + " " + lname);
            osUser.setEmail(email);

            Group jiraUserGroup = userMgr.getGroup("jira-users");
            osUser.addToGroup(jiraUserGroup);
            osUser.store();
            log.debug("Successfully added LDAP user "+ userId);
        } catch (ImmutableException e) {
            log.error("Error creating User in Jira: " + userId, e);
        } catch (DuplicateEntityException e) {
            log.error("Error creating User in Jira: " + userId, e);
        } catch (EntityNotFoundException e) {
            log.error("Could not find group jira-users.  Error creating User in Jira: " + userId, e);
        }

        // to be sure the user was created, return the reloaded user from Jira
        return osUser;

    }

    private boolean userExists(String userId) {
        UserManager userMgr = UserManager.getInstance();
        boolean exists = false;
        try {
            if(userMgr.getUser(userId) != null)
                exists = true;
        } catch (EntityNotFoundException e) {
            exists = false;
        }

        return exists;
    }

    private void addUserGroup(String userId, String groupName){
        UserManager userMgr = UserManager.getInstance();

        try {
            User osUser = userMgr.getUser(userId);

            Group group = userMgr.getGroup(groupName);
            osUser.addToGroup(group);
            osUser.store();
            log.debug("Successfully added LDAP user " + userId + " to group: " + groupName);
        } catch (ImmutableException e) {
            log.error("Error adding User to acis-users group: " + userId, e);
        } catch (EntityNotFoundException e) {
            log.error("Could not find group acis-users.  Error adding User to acis-users group:  " + userId, e);
        }
    }

    public ObjectConfiguration getObjectConfiguration() throws ObjectConfigurationException {
        return getObjectConfiguration("LDAPUSERSYNCSERVICE", "com/myco/jira/service/LDAPUserSyncService.xml", null);
    }
}
</pre>
<p>To configure a service within Jira navigate to Services in the System section of the Administration interface:<br />
<center><img src="/wp-content/uploads/2008/04/jira-services-menu.png" alt="" title="jira-services-menu" width="189" height="272" class="aligncenter size-full wp-image-124 colorbox-123" /></center></p>
<p>Here I&#8217;ve added the service you can see the parameters that can be customized for the service:<br />
<img src="http://mike.brevoort.com/wp-content/uploads/2008/04/jira-service-ldap.png" alt="" title="jira-service-ldap" width="500" height="103" class="aligncenter size-full wp-image-125 colorbox-123" /></p>
<p>The parameters are configured in an XML file that is referenced by the getObjectConfiguration() method in the service code above: </p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;debugservice id="LDAPUserSyncService"&gt;
    &lt;description&gt;
    &lt;/description&gt;
    &lt;properties&gt;

        &lt;property&gt;
            &lt;key&gt;LDAP_HOST&lt;/key&gt;
            &lt;name&gt;LDAP Host (format: ldap://myco.com:389)&lt;/name&gt;
            &lt;type&gt;string&lt;/type&gt;
        &lt;/property&gt;
        &lt;property&gt;
            &lt;key&gt;LDAP_USER&lt;/key&gt;
            &lt;name&gt;LDAP User DN&lt;/name&gt;
            &lt;type&gt;string&lt;/type&gt;
        &lt;/property&gt;
                &lt;property&gt;
            &lt;key&gt;LDAP_PASSWORD&lt;/key&gt;
            &lt;name&gt;LDAP Password)&lt;/name&gt;
            &lt;type&gt;string&lt;/type&gt;
        &lt;/property&gt;
        &lt;property&gt;
            &lt;key&gt;LDAP_SEARCHBASE&lt;/key&gt;
            &lt;name&gt;LDAP Search Base DN&lt;/name&gt;
            &lt;type&gt;string&lt;/type&gt;
        &lt;/property&gt;
        &lt;property&gt;
            &lt;key&gt;LDAP_FILTER&lt;/key&gt;
            &lt;name&gt;LDAP Search Filter&lt;/name&gt;
            &lt;type&gt;string&lt;/type&gt;
        &lt;/property&gt;

    &lt;/properties&gt;
&lt;/debugservice&gt;
</pre>
<p>And that&#8217;s it.  New users are automatically created in Jira within 30 minutes of being created in LDAP.  Ooo Rah.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/&amp;t=Expanding+on+Jira%27s+LDAP+Integration" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Expanding+on+Jira%27s+LDAP+Integration+-+http://bit.ly/4DGBKw+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/&amp;title=Expanding+on+Jira%27s+LDAP+Integration&amp;summary=I%20recently%20had%20the%20opportunity%20to%20do%20a%20fresh%20installation%20of%20Atlassian%20Jira%20and%20was%20faced%20again%20with%20how%20to%20integrate%20Jira%20with%20LDAP%20%28in%20this%20case%20Active%20Directory%29.%20%20Jira%20does%20support%20simple%20authentication%20integration%20with%20LDAP%20via%20OSUser%20but%20requires%20that%20each%20LDAP%20user%20exist%20in%20Jira%20first.%20%20So%20if&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Expanding+on+Jira%27s+LDAP+Integration&amp;link=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/&amp;title=Expanding+on+Jira%27s+LDAP+Integration" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/&amp;submitHeadline=Expanding+on+Jira%27s+LDAP+Integration&amp;submitSummary=I%20recently%20had%20the%20opportunity%20to%20do%20a%20fresh%20installation%20of%20Atlassian%20Jira%20and%20was%20faced%20again%20with%20how%20to%20integrate%20Jira%20with%20LDAP%20%28in%20this%20case%20Active%20Directory%29.%20%20Jira%20does%20support%20simple%20authentication%20integration%20with%20LDAP%20via%20OSUser%20but%20requires%20that%20each%20LDAP%20user%20exist%20in%20Jira%20first.%20%20So%20if&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/&amp;title=Expanding+on+Jira%27s+LDAP+Integration" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Expanding%20on%20Jira%27s%20LDAP%20Integration%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%20recently%20had%20the%20opportunity%20to%20do%20a%20fresh%20installation%20of%20Atlassian%20Jira%20and%20was%20faced%20again%20with%20how%20to%20integrate%20Jira%20with%20LDAP%20%28in%20this%20case%20Active%20Directory%29.%20%20Jira%20does%20support%20simple%20authentication%20integration%20with%20LDAP%20via%20OSUser%20but%20requires%20that%20each%20LDAP%20user%20exist%20in%20Jira%20first.%20%20So%20if%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/04/08/syncing-jira-with-ldap/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Part 2: Terracotta: 1, Grails Searchable Plugin+Me: 1</title>
		<link>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/</link>
		<comments>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 00:36:56 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[terracotta]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/</guid>
		<description><![CDATA[Round Two of my quest to cluster the Grails Searchable Plugin index with Terracotta! In my first post I outlined my intent to use Terracotta to cluster the Grails Searchable Plugin (Lucene + Compass) using the Lucene RAMDirectory approach. Incidentally, my first attempt failed miserably. As a quick confidence booster before setting out again, I [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F29%2Fterracotta-1-grails-searchable-pluginme-1%2F"><br />
				<img class="colorbox-112"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F29%2Fterracotta-1-grails-searchable-pluginme-1%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>Round Two of my quest to cluster the <a href="http://grails.codehaus.org/Searchable+Plugin">Grails Searchable Plugin</a> index with Terracotta!  In <a href="http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/">my first post</a> I outlined my intent to use <a href="http://www.terracotta.org">Terracotta</a> to cluster the Grails Searchable Plugin (<a href="http://www.google.com/url?sa=t&#038;ct=res&#038;cd=2&#038;url=http%3A%2F%2Flucene.apache.org%2F&#038;ei=F72fR6mANY-4gQTJweS1Bw&#038;usg=AFQjCNFlWzRUABueiSQ0PYLo1g0KjXCBRw&#038;sig2=TXtJGiDzcEqX2_NScUhT1Q">Lucene</a> + <a href="http://www.google.com/url?sa=t&#038;ct=res&#038;cd=1&#038;url=http%3A%2F%2Fwww.opensymphony.com%2Fcompass%2F&#038;ei=Br2fR6f-EabMgQSgrP27Bw&#038;usg=AFQjCNFWrf7kReBpKrslhJMYYfgcC03KXQ&#038;sig2=Zggi_LhkubznLIr6dGQwzA">Compass</a>) using the <a href="http://www.terracotta.org/confluence/display/integrations/Lucene">Lucene RAMDirectory</a> approach.  Incidentally, my first attempt failed miserably.</p>
<p>As a quick confidence booster before setting out again, I <a href="http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/">successfully clustered the Grails Searchable Plugin using a JDBCDirectory store</a> for the index.  Since my last attempt I received some <a href="http://www.nabble.com/Compass%2C-Lucene-and-Grails-Searchable-Plugin-td15021230.html">guidance from the guys at Terracotta</a> and learned that <a href="http://www.kimchy.org/">Shay Banon</a> is working with Terrocotta to develop a Compass module for Terracotta.  Good stuff&#8230; check out the details of that <a href="http://www.nabble.com/FYI-on-Compass---Lucene-Integration-td15094091.html">here</a>. </p>
<p>The first hurdle I needed to overcome was the classloader error:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
Classloader name not set, instances defined from this
loader not supported in Terracotta
(loader: org.codehaus.groovy.grails.cli.support.GrailsRootLoader)
</pre>
<p>Before an object can be shared by Terracotta, the ClassLoader that loaded the object&#8217;s class has to be known to Terracotta. For core java and supported frameworks/container Terracotta takes care of registering relevant classloaders.  For the GrailsRootLoader I can do this one of two ways: </p>
<ol>
<li>hack the grails source where the class loader is instantiated, registering it with Terracotta</li>
<li>this can be converted into a config module that will inject the proper byte code at runtime so as to avoid any code tweaking.  </li>
</ol>
<p>The guys at Terracotta offered to help with #2 if I could get #1 working.</p>
<p>So I checked out the Grail trunk from SVN, and added these lines after the GrailsRootLoader is created:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
 // create loader and execute main class
GrailsRootLoader loader = new GrailsRootLoader(lc);
((com.tc.object.loaders.NamedClassLoader) loader).__tc_setClassLoaderName("Grail Classloader");
com.tc.object.bytecode.hook.impl.ClassProcessorHelper.registerGlobalLoader((com.tc.object.loaders.NamedClassLoader) loader);
</pre>
<p>I built the Grails jars and replaced them in my grails-1.0-final-SNAPSHOT/dist directory.  That resolved my classloader error!  Next I went through about 100 iterations of root and lock configuration for my tc-config.xml as I dug and spun my way around the Compass source.  I finally ended up with this for my tc-config.xml (keep in mind this can surely be optimized and is pretty brute force):</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;

&lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&gt;
  &lt;system&gt;
    &lt;configuration-model&gt;development&lt;/configuration-model&gt;
  &lt;/system&gt;

  &lt;servers&gt;
    &lt;server name="localhost" /&gt;
  &lt;/servers&gt;

  &lt;clients&gt;
    &lt;logs&gt;%d/client-logs-%h&lt;/logs&gt;
    &lt;dso&gt;

       &lt;debugging&gt;
        &lt;runtime-logging&gt;
          &lt;lock-debug&gt;true&lt;/lock-debug&gt;
        &lt;/runtime-logging&gt;
        &lt;runtime-output-options&gt;
          &lt;full-stack&gt;true&lt;/full-stack&gt;
        &lt;/runtime-output-options&gt;
      &lt;/debugging&gt;

    &lt;/dso&gt;
    &lt;modules&gt;
      &lt;module name="clustered-lucene-2.0.0" version="2.5.0"/&gt;
    &lt;/modules&gt;
  &lt;/clients&gt;

  &lt;application&gt;
    &lt;dso&gt;
      &lt;instrumented-classes&gt;
        &lt;include&gt;
          &lt;class-expression&gt;org.compass.core.lucene.engine..*&lt;/class-expression&gt;
        &lt;/include&gt;
        &lt;include&gt;
          &lt;class-expression&gt;org.apache.lucene..*&lt;/class-expression&gt;
        &lt;/include&gt;
      &lt;/instrumented-classes&gt;
      &lt;roots&gt;
        &lt;root&gt;
          &lt;field-name&gt;org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore.ramIndexes&lt;/field-name&gt;
        &lt;/root&gt;
      &lt;/roots&gt;
      &lt;locks&gt;
	&lt;named-lock&gt;
          &lt;method-expression&gt;* org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager.*(..)&lt;/method-expression&gt;
          &lt;lock-level&gt;write&lt;/lock-level&gt;
          &lt;lock-name&gt;theLockName&lt;/lock-name&gt;
        &lt;/named-lock&gt;
        &lt;/locks&gt;
     &lt;/dso&gt;
  &lt;/application&gt;
&lt;/tc:tc-config&gt;
</pre>
<p>It worked!  I was able to test with the Terracotta server running, and two Grails apps running in separate JVMs that all of the Domain class data that the first JVM indexed, could be searched by the second JVM and they both returned identical results.  I also verified the existence of the objects under the root in the Terracotta Admin GUI.  And finally, I shut both Grails app JVMs down and brought them back up and my index was still available.  </p>
<p>What&#8217;s next?  Work to get a config module for Terracotta and optimize my root and locking configuration.  I&#8217;m very interested in what will come of the promised Compass/Terracotta integration.  Also Clustering Grails is a much taller mountain.  I was told that past attempts to cluster Groovy with Terracotta had not been too successful.  For now I&#8217;m happy just to have climbed my little hill&#8230;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/&amp;t=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1+-+http://bit.ly/4dMIXV+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/&amp;title=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1&amp;summary=Round%20Two%20of%20my%20quest%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20index%20with%20Terracotta%21%20%20In%20my%20first%20post%20I%20outlined%20my%20intent%20to%20use%20Terracotta%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20%28Lucene%20%2B%20Compass%29%20using%20the%20Lucene%20RAMDirectory%20approach.%20%20Incidentally%2C%20my%20first%20attempt%20failed%20miserably.%0D%0A%0D%0AAs%20a%20q&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1&amp;link=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/&amp;title=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/&amp;submitHeadline=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1&amp;submitSummary=Round%20Two%20of%20my%20quest%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20index%20with%20Terracotta%21%20%20In%20my%20first%20post%20I%20outlined%20my%20intent%20to%20use%20Terracotta%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20%28Lucene%20%2B%20Compass%29%20using%20the%20Lucene%20RAMDirectory%20approach.%20%20Incidentally%2C%20my%20first%20attempt%20failed%20miserably.%0D%0A%0D%0AAs%20a%20q&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/&amp;title=Part+2%3A+Terracotta%3A+1%2C+Grails+Searchable+Plugin%2BMe%3A+1" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Part%202%3A%20Terracotta%3A%201%2C%20Grails%20Searchable%20Plugin%2BMe%3A%201%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22Round%20Two%20of%20my%20quest%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20index%20with%20Terracotta%21%20%20In%20my%20first%20post%20I%20outlined%20my%20intent%20to%20use%20Terracotta%20to%20cluster%20the%20Grails%20Searchable%20Plugin%20%28Lucene%20%2B%20Compass%29%20using%20the%20Lucene%20RAMDirectory%20approach.%20%20Incidentally%2C%20my%20first%20attempt%20failed%20miserably.%0D%0A%0D%0AAs%20a%20q%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Using JDBCDirectory with the Grails Searable Plugin</title>
		<link>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/</link>
		<comments>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/#comments</comments>
		<pubDate>Fri, 25 Jan 2008 04:05:34 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[lucene]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/</guid>
		<description><![CDATA[In my last post I mentioned that one of the options I was considering for clustering the Grails Searchable plugin, though not the preferred option, was to use the JDBCDirectory implementation of Lucene. I had this working in just 15 minutes and though it&#8217;s probably not the optimal approach, it is by far the simplest. [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F24%2Fusing-jdbcdirectory-with-the-grails-searable-plugin%2F"><br />
				<img class="colorbox-111"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F24%2Fusing-jdbcdirectory-with-the-grails-searable-plugin%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>In my <a href="http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/">last post</a> I mentioned that one of the options I was considering for clustering the Grails Searchable plugin, though not the preferred option, was to use the <a href="http://www.opensymphony.com/compass/versions/0.9.0/api/org/apache/lucene/store/jdbc/JdbcDirectory.html">JDBCDirectory</a> implementation of Lucene.  I had this working in just 15 minutes and though it&#8217;s probably not the optimal approach, it is by far the simplest.</p>
<p>Just to set the stage, I&#8217;m running Grails RC3, Groovy 1.5.1, JDK 1.6, grails-searchable-0.4-SNAPSHOT and MySQL 5.0.45.  I will configure the <a href="http://www.opensymphony.com/compass/">Compass</a> to use the JdbcDirectory connection instead of file or ram and test that it can be updated and read by two instances of my Grails application.</p>
<p>First I created compass.cfg.xml in grails-app/conf (just needs to be somewhere in the classpath) with jdbc connection details:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;compass-core-config xmlns="http://www.opensymphony.com/compass/schema/core-config"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config
          http://www.opensymphony.com/compass/schema/compass-core-config.xsd"&gt;
   &lt;compass name="default"&gt;
     &lt;connection&gt;
         &lt;jdbc dialect="org.apache.lucene.store.jdbc.dialect.MySQLDialect"&gt;
             &lt;dataSourceProvider&gt;
                 &lt;driverManager url="jdbc:mysql://localhost/search?emulateLocators=true"
                                      username="root" password="password"
                                      driverClass="com.mysql.jdbc.Driver" /&gt;
             &lt;/dataSourceProvider&gt;
             &lt;fileEntries&gt;
                 &lt;fileEntry name="__default__"&gt;
                     &lt;indexInput bufferSize="4096" /&gt;
                     &lt;indexOutput bufferSize="4096" /&gt;
                 &lt;/fileEntry&gt;
             &lt;/fileEntries&gt;
         &lt;/jdbc&gt;
     &lt;/connection&gt;
   &lt;/compass&gt;
&lt;/compass-core-config&gt;
</pre>
<p>One thing I missed at first was the dialect setting in the jdbc tag.  Make sure you select the correct dialect for your database.  I used <a href="http://static.compassframework.org/docs/latest/jdbcdirectory.html">this as a reference</a>.<br />
In SearchableConfiguration.groovy I set compassConnection to null</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
String compassConnection = null
</pre>
<p>I started my grails app and hit just one more snag, I got a &#8220;packet too large&#8221; error while it was building the index.  Turns out the default max_allowed_packet in MySQL on the server is 1M and since Lucene stores parts of the index in BLOBs I needed to up the max.  I found <a href="http://dev.mysql.com/doc/refman/5.0/en/packet-too-large.html">this article</a> and set the max_allowed_packet setting to 16M.  I did this in my.ini:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
[mysqld]
max_allowed_packet=16M
</pre>
<p>That was it!  I tested by running two instances of my Grails application simultaneously and I modified one of my Domain class instances and executed a search on the other instance and within a few seconds, the new value was returned in my search.</p>
<p>The last thing I considered was configuring a <a href="http://www.opensymphony.com/compass/versions/1.2/html/core-connection.html#core-connection-localcache">Local Directory Cache</a> in Compass.  This seemed like it could offer some good optimization though it was unclear from the documentation how much control you have over the size of the cache, what gets cached, the TTL, etc.  Also, I soon realized that this was introduced in the latest version of Compass (1.2) and isn&#8217;t  the version that is bundled in the Searchable plugin.  </p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/&amp;t=Using+JDBCDirectory+with+the+Grails+Searable+Plugin" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Using+JDBCDirectory+with+the+Grails+Searable+Plugin+-+http://bit.ly/e5QCt+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/&amp;title=Using+JDBCDirectory+with+the+Grails+Searable+Plugin&amp;summary=In%20my%20last%20post%20I%20mentioned%20that%20one%20of%20the%20options%20I%20was%20considering%20for%20clustering%20the%20Grails%20Searchable%20plugin%2C%20though%20not%20the%20preferred%20option%2C%20was%20to%20use%20the%20JDBCDirectory%20implementation%20of%20Lucene.%20%20I%20had%20this%20working%20in%20just%2015%20minutes%20and%20though%20it%27s%20probably%20not%20the%20optimal%20approach%2C%20it%20is%20b&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Using+JDBCDirectory+with+the+Grails+Searable+Plugin&amp;link=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/&amp;title=Using+JDBCDirectory+with+the+Grails+Searable+Plugin" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/&amp;submitHeadline=Using+JDBCDirectory+with+the+Grails+Searable+Plugin&amp;submitSummary=In%20my%20last%20post%20I%20mentioned%20that%20one%20of%20the%20options%20I%20was%20considering%20for%20clustering%20the%20Grails%20Searchable%20plugin%2C%20though%20not%20the%20preferred%20option%2C%20was%20to%20use%20the%20JDBCDirectory%20implementation%20of%20Lucene.%20%20I%20had%20this%20working%20in%20just%2015%20minutes%20and%20though%20it%27s%20probably%20not%20the%20optimal%20approach%2C%20it%20is%20b&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/&amp;title=Using+JDBCDirectory+with+the+Grails+Searable+Plugin" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Using%20JDBCDirectory%20with%20the%20Grails%20Searable%20Plugin%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22In%20my%20last%20post%20I%20mentioned%20that%20one%20of%20the%20options%20I%20was%20considering%20for%20clustering%20the%20Grails%20Searchable%20plugin%2C%20though%20not%20the%20preferred%20option%2C%20was%20to%20use%20the%20JDBCDirectory%20implementation%20of%20Lucene.%20%20I%20had%20this%20working%20in%20just%2015%20minutes%20and%20though%20it%27s%20probably%20not%20the%20optimal%20approach%2C%20it%20is%20b%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Building Grails Applications with Hudson</title>
		<link>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/</link>
		<comments>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/#comments</comments>
		<pubDate>Mon, 21 Jan 2008 18:33:10 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[hudson]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/</guid>
		<description><![CDATA[I&#8217;m never surprised by the shear magnitude of stuff I don&#8217;t know about. Last week I stumbled upon Hudson as I was searching for help to configure Cruise Control to build and execute tests for my a Grails application. I found this post that introduced me to Hudson and got me started. Let me first [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F21%2Fbuilding-grails-applications-with-hudson%2F"><br />
				<img class="colorbox-108"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2008%2F01%2F21%2Fbuilding-grails-applications-with-hudson%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>I&#8217;m never surprised by the shear magnitude of stuff I don&#8217;t know about.  Last week I stumbled upon <a href="https://hudson.dev.java.net/">Hudson</a> as I was searching for help to configure <a href="http://cruisecontrol.sourceforge.net/">Cruise Control</a> to build and execute tests for my  a <a href="http://grails.codehaus.org/">Grails</a> application.  I found <a href="http://www.giolist.com/2008_01_01_giolist-archive.html">this post</a> that introduced me to Hudson and got me started.</p>
<p>Let me first say that I was off to find a free solution.  If I had the luxury of spending a little cash at this point I would have used <a href="http://www.atlassian.com/software/bamboo/">Bamboo</a>.  I&#8217;m a big fan of <a href="http://www.atlassian.com">Atlassian</a> products and love what they are doing to integrate Jira, Fisheye, Bamboo, Crucible, Clover and Confluence.  The traceability of code to issues to change sets to builds and tests is really cool.  Anyway I digress.  </p>
<p>So I found Hudson, and I was pleasantly surprised how easy it was to set up.  I&#8217;m running on Windows with Tomcat 6 and JDK1.6.  I simply deployed the Hudson WAR, and I was off to the races.  Hudson&#8217;s configuration is all done via a web interface and the interface itself is very clean, especially compared to Cruise Control.  </p>
<p>In Hudson I created a new job, selected SVN in the source code management section and entered the URL to my Grails app in the repository.  Hudson also lets you configure a repository browser (ViewSVN, Fisheye, WebSVN or Sventon).  Since I was already running Tomcat, I chose Sventon and quickly downloaded and deployed the WAR for <a href="http://www.sventon.org/">Sventon</a>.  I set Hudson to poll SVN for changes every minute and for the build itself I told Hudson to use Ant (you need to set up ANT first in Hudsson) and pointed to the Grails build.xml.  </p>
<p>I created two new targets in the build.xml: &#8216;all&#8217; and &#8216;deploy&#8217;.  The all target chains the depended targets together.  I had originally had Hudson call test, war, deploy and doc separately but each invoked a compile separately.</p>
<pre class="prettyprint" style="width:500px;font-size:11px;overflow:auto">
&lt;target name="all" depends="war, test, deploy, doc"
  description="build, test, deploy and build the javadoc"/&gt;
</pre>
<p>I also created a deploy target that takes the war and deploys to Tomcat and property to specify the grails_env.</p>
<p>Under Post-build Actions I set the following properties:</p>
<ul>
<li>Files to Archive = &#8220;**/*.war&#8221;</li>
<li>Javadoc Directory = &#8220;GRAILS-APP/docs/gapi&#8221;</li>
<li>Test Reports XMLs = &#8220;GRAILS-APP/test/reports/*.xml&#8221;</li>
</ul>
<p>So in about an hour I had Hudson continually building, running my test cases, generating javadoc and deploying my WAR to Tomcat, and it was all relatively painless.  Here&#8217;s what the job status screen looks like:<br />
<img class="colorbox-108"  src='http://mike.brevoort.com/wp-content/uploads/2008/01/hudson_sh.png' alt='Hudson Screenshot' /></p>
<p>Going forward I&#8217;ll probably investigate using <a href="http://weblogs.java.net/blog/kohsuke/archive/2007/07/hudson_gant_plu.html">GANT instead of ANT</a>, otherwise it&#8217;s serving the purpose.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/&amp;t=Building+Grails+Applications+with+Hudson" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Building+Grails+Applications+with+Hudson+-+http://bit.ly/2mLVQ1+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/&amp;title=Building+Grails+Applications+with+Hudson&amp;summary=I%27m%20never%20surprised%20by%20the%20shear%20magnitude%20of%20stuff%20I%20don%27t%20know%20about.%20%20Last%20week%20I%20stumbled%20upon%20Hudson%20as%20I%20was%20searching%20for%20help%20to%20configure%20Cruise%20Control%20to%20build%20and%20execute%20tests%20for%20my%20%20a%20Grails%20application.%20%20I%20found%20this%20post%20that%20introduced%20me%20to%20Hudson%20and%20got%20me%20started.%0D%0A%0D%0ALet%20me%20fir&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Building+Grails+Applications+with+Hudson&amp;link=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/&amp;title=Building+Grails+Applications+with+Hudson" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/&amp;submitHeadline=Building+Grails+Applications+with+Hudson&amp;submitSummary=I%27m%20never%20surprised%20by%20the%20shear%20magnitude%20of%20stuff%20I%20don%27t%20know%20about.%20%20Last%20week%20I%20stumbled%20upon%20Hudson%20as%20I%20was%20searching%20for%20help%20to%20configure%20Cruise%20Control%20to%20build%20and%20execute%20tests%20for%20my%20%20a%20Grails%20application.%20%20I%20found%20this%20post%20that%20introduced%20me%20to%20Hudson%20and%20got%20me%20started.%0D%0A%0D%0ALet%20me%20fir&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/&amp;title=Building+Grails+Applications+with+Hudson" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Building%20Grails%20Applications%20with%20Hudson%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%27m%20never%20surprised%20by%20the%20shear%20magnitude%20of%20stuff%20I%20don%27t%20know%20about.%20%20Last%20week%20I%20stumbled%20upon%20Hudson%20as%20I%20was%20searching%20for%20help%20to%20configure%20Cruise%20Control%20to%20build%20and%20execute%20tests%20for%20my%20%20a%20Grails%20application.%20%20I%20found%20this%20post%20that%20introduced%20me%20to%20Hudson%20and%20got%20me%20started.%0D%0A%0D%0ALet%20me%20fir%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Active Directory Authentication Part I</title>
		<link>http://mike.brevoort.com/2007/09/25/active-directory-authentication/</link>
		<comments>http://mike.brevoort.com/2007/09/25/active-directory-authentication/#comments</comments>
		<pubDate>Wed, 26 Sep 2007 05:14:14 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2007/09/25/active-directory-authentication/</guid>
		<description><![CDATA[One of the main reasons I started this blog was so that I would have a place to &#8220;give back&#8221; to the software development community. For those that read my blog for more personal updates, you&#8217;ll want to stop here. My daily work life depends heavily on open source projects, discussion forums and blogs posts [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fmike.brevoort.com%2F2007%2F09%2F25%2Factive-directory-authentication%2F"><br />
				<img class="colorbox-88"  src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fmike.brevoort.com%2F2007%2F09%2F25%2Factive-directory-authentication%2F&amp;source=mbrevoort&amp;style=normal&amp;service=bit.ly&amp;service_api=R_53b3b24869237bc468fdaf2c7a85a46f" height="61" width="50" /><br />
			</a>
		</div>
<p>One of the main reasons I started this blog was so that I would have a place to &#8220;give back&#8221; to the software development community.  For those that read my blog for more personal updates, you&#8217;ll want to stop here.  My daily work life depends heavily on open source projects, discussion forums and blogs posts like this one.  In this post I&#8217;ll be sharing what I&#8217;ve learned regarding programmatic authentication to Active Directory for a custom website authentication scheme. </p>
<p>I recently redeveloped a centralized web-based authentication service for a large corporate intranet that leveraged <a href="http://www.rsa.com/node.aspx?id=1186">RSA Access Manager</a> as a web single sign-on (SSO) provider.  The authentication service validates credentials against Active Directory and handles cases of expired password resets and locked accounts.  Once a credential has been validated, the user Id is asserted to RSA Access Manager, creating a new session and then passing control over to RSA and redirecting onto the requested resource.  </p>
<p>A few key points:</p>
<li>RSA Access Manager is a Java based application and all of the intranet applications are Java applications</li>
<li>The Active Directory forest has 42 child domains organized by business unit, all de-centrally administered, spread across the US in 18 states and connected by a wide area network with relatively high latency.</li>
<li>Across the 42 domains, there are well over 100 domain controllers, some Windows 2003, others Windows 2000</li>
<p>As I am a Java developer with no previous .Net experience, the first attempt to externalize authentication from RSA Access Manager was in Java via JAAS/GSS-API and then JNDI.  Without going into detail, this turned out to be difficult given the diversity of the AD infrastructure.  </p>
<p>Next, since we had other needs to interface with Active Directory from our applications, I decided on a new approach.  I developed a .Net Web Services API in C# to interface with our Active Directory infrastructure.  The Web Services API encapsulated the complexity of the environment and allowed the caller to search, retrieve, and manipulate AD users and group information.  This is now how we integrate our Java applications with AD.  As part of this implementation in the same ASP.Net web application, I implemented the centralized authentication HTML service.  Next I&#8217;ll dive into three iterations of the authentication functionality.  I&#8217;ll save anything outside of the authentication portion for other posts if there&#8217;s interest.</p>
<p>The first iteration leveraged Integrated Windows Authentication (IWA) via IIS.  I won&#8217;t go into detail on this but will say we abandoned that approach because of the regular use of shared workstations and auto-login accounts.</p>
<p>The second iteration used LDAP via ADSI:<br />
Given a domain, samAccountName and password, attempt to bind to the root of the domain of the user.  If successful, continue. If the bind failed, one of these cases is true: the credential was invalid, the account password is expired (including &#8220;must change password on next login&#8221; situations, the account is locked (too many bad attempts) or the account is disabled.  Therefore, bind with a known system credential to check the account status.  If the account password is expired, notify the user and prompt the user to reset their password.  Otherwise, if the account is locked, disabled, or looks OK, return that the authentication was unsuccessful.</p>
<p>Below are several snippets of code:</p>
<pre class="prettyprint" style="width:500px;font-size:11px;overflow:auto">
public static AuthenticationResult authAndStatus(string domain, string samAccountName,
    string password, String adminUsername, String adminPassword)
{
    String domainAndUsername = domain + "\\\\" + samAccountName;
    DirectoryEntry de = getDirectoryEntry(domain, domainAndUsername, password);
    AuthenticationResult result = new AuthenticationResult();
    DirectoryEntry userDE = null;

    try
    {
        // Bind to the native AdsObject to force authentication.
        Object obj = de.NativeObject;
        result.authResult = AuthenticationResult.SUCCESSFUL;

    }
    catch (Exception ex)
    {
        // the bind failed
        result.authResult = AuthenticationResult.FAILED;
    }

    try
    {
        // get the account status
        de = getDirectoryEntry(domain, adminUsername, adminPassword);
        userDE = ADUtilities.getUserDE(de, "samAccountName", samAccountName,
            adminUsername, adminPassword);
        if (userDE != null)
        {
            AccountStatus accountStatus = new AccountStatus(userDE);
            result.accountStatus = accountStatus;
        }
        else
        {
            result.authResult = AuthenticationResult.INVALID;
        }
    }
    catch (Exception ex)
    {
        // need to trap, basically don't let the status check break
        //the authentication
    }

    return result;
}
</pre>
<pre class="prettyprint"  style="width:500px;font-size:11px">
    public static DirectoryEntry getUserDE(DirectoryEntry de, String propertyName, String propertyValue, String adminUsername, String adminPassword)
    {
        DirectorySearcher search = new DirectorySearcher(de);
        search.Filter = "(" + propertyName + "=" + propertyValue + ")";

        SearchResult result = search.FindOne();
        if (result != null) {
            return new DirectoryEntry(result.Path, adminUsername, adminPassword);
        } else {
            return null;
        }
    }

public static DirectoryEntry getDirectoryEntry(String domain, String adminUsername, String adminPassword)
{
    String dePath = null;

    String adForestName = (String)System.AppDomain.CurrentDomain.GetData("adForestName");
    String forestDomainName = adForestName.Substring(0, adForestName.IndexOf('.'));
    String gcDNS = (String)System.AppDomain.CurrentDomain.GetData("adForestPreferredGlobalCatalog");

    if (domain != null &#038;&#038; domain.ToUpper().Contains(".") &#038;&#038; domain.ToUpper().Contains(adForestName.ToUpper()))
    {
        domain = (domain.Split(new char[] { '.' }))[0];
    }

    // if the domain is not null and not All
    if (domain != null &#038;&#038; !domain.Trim().Equals("") &#038;&#038; !domain.Equals("All"))
    {
        String fqdn = domain + "." + adForestName;

        // check if this is the root domain and if so rest the fqdn to the forest name
        if (domain.ToUpper().Equals(forestDomainName.ToUpper()))
            fqdn = adForestName;

        String ldapDCs = getLDAPDCs(fqdn);
        dePath = "LDAP://" + fqdn + "/" + ldapDCs;

    }
    else
    {
        String ldapDCs = getLDAPDCs(adForestName);
        // if the domain is null assume the global catalog
        dePath = "LDAP://" + gcDNS + ":3268/" + ldapDCs;
    }

    DirectoryEntry de = new DirectoryEntry(dePath, adminUsername, adminPassword, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
    return de;

}

public static DirectoryEntry getGCDirectoryEntryForDomain(String domain, String adminUsername, String adminPassword)
{
    String dePath = null;

    String adForestName = (String)System.AppDomain.CurrentDomain.GetData("adForestName");
    String forestDomainName = adForestName.Substring(0, adForestName.IndexOf('.'));
    String gcDNS = (String)System.AppDomain.CurrentDomain.GetData("adForestPreferredGlobalCatalog");

    dePath = "LDAP://" + gcDNS + ":3268/" + getLDAPDCs(domain + "." + adForestName);

    DirectoryEntry de = new DirectoryEntry(dePath, adminUsername, adminPassword, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
    return de;

}

public static String getLDAPDCs(String fqdn)
{
    String ldapDCs = "";

    if (fqdn != null) {
        char[] separator = new char[1];
        separator[0] = '.';
        String[] parts = fqdn.Split(separator);

        for (int i = 0; i < parts.Length; i++) {
            ldapDCs = ldapDCs + "dc=" + parts[i];

            if (i + 1 != parts.Length)
                ldapDCs = ldapDCs + ",";
        }
    }

    return ldapDCs;
}
</pre>
<p>In my next post I describe how well this approach actually worked and the issues that prompted the search for another solution.  Then I'll go into using SSPI and then the use of the LogonUser native function call...</p>
<p>I FINALLY posted a follow-up to this <a href="http://mike.brevoort.com/2008/09/27/active-directory-authentication-part-ii/">here</a></pre>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-enjoy">
<ul class="socials">
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://mike.brevoort.com/2007/09/25/active-directory-authentication/&amp;t=Active+Directory+Authentication+Part+I" rel="nofollow" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Active+Directory+Authentication+Part+I+-+http://bit.ly/2WxJdp+(via+@mbrevoort)&amp;source=shareaholic" rel="nofollow" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://mike.brevoort.com/2007/09/25/active-directory-authentication/&amp;title=Active+Directory+Authentication+Part+I&amp;summary=One%20of%20the%20main%20reasons%20I%20started%20this%20blog%20was%20so%20that%20I%20would%20have%20a%20place%20to%20%22give%20back%22%20to%20the%20software%20development%20community.%20%20For%20those%20that%20read%20my%20blog%20for%20more%20personal%20updates%2C%20you%27ll%20want%20to%20stop%20here.%20%20My%20daily%20work%20life%20depends%20heavily%20on%20open%20source%20projects%2C%20discussion%20forums%20and%20blog&amp;source=m i k e  b r e v o o r t" rel="nofollow" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-friendfeed">
			<a href="http://www.friendfeed.com/share?title=Active+Directory+Authentication+Part+I&amp;link=http://mike.brevoort.com/2007/09/25/active-directory-authentication/" rel="nofollow" title="Share this on FriendFeed">Share this on FriendFeed</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://mike.brevoort.com/2007/09/25/active-directory-authentication/" rel="nofollow" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://mike.brevoort.com/2007/09/25/active-directory-authentication/&amp;title=Active+Directory+Authentication+Part+I" rel="nofollow" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-yahoobuzz">
			<a href="http://buzz.yahoo.com/submit/?submitUrl=http://mike.brevoort.com/2007/09/25/active-directory-authentication/&amp;submitHeadline=Active+Directory+Authentication+Part+I&amp;submitSummary=One%20of%20the%20main%20reasons%20I%20started%20this%20blog%20was%20so%20that%20I%20would%20have%20a%20place%20to%20%22give%20back%22%20to%20the%20software%20development%20community.%20%20For%20those%20that%20read%20my%20blog%20for%20more%20personal%20updates%2C%20you%27ll%20want%20to%20stop%20here.%20%20My%20daily%20work%20life%20depends%20heavily%20on%20open%20source%20projects%2C%20discussion%20forums%20and%20blog&amp;submitCategory=science&amp;submitAssetType=text" rel="nofollow" title="Buzz up!">Buzz up!</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://mike.brevoort.com/2007/09/25/active-directory-authentication/&amp;title=Active+Directory+Authentication+Part+I" rel="nofollow" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Active%20Directory%20Authentication%20Part%20I%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22One%20of%20the%20main%20reasons%20I%20started%20this%20blog%20was%20so%20that%20I%20would%20have%20a%20place%20to%20%22give%20back%22%20to%20the%20software%20development%20community.%20%20For%20those%20that%20read%20my%20blog%20for%20more%20personal%20updates%2C%20you%27ll%20want%20to%20stop%20here.%20%20My%20daily%20work%20life%20depends%20heavily%20on%20open%20source%20projects%2C%20discussion%20forums%20and%20blog%22%0A%0AYou+can+read+the+full+article+here%3A%20http://mike.brevoort.com/2007/09/25/active-directory-authentication/" rel="nofollow" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2007/09/25/active-directory-authentication/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
