<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Blogs at Near Infinity</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/" />
    <link rel="self" type="application/atom+xml" href="http://www.nearinfinity.com/blogs/atom.xml" />
    <id>tag:www.nearinfinity.com,2007-12-20:/blogs/7</id>
    <updated>2010-02-03T20:00:25Z</updated>
    <subtitle>Employee Blogs</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.31-en</generator>

<entry>
    <title>Sharepoint ASP .Net Ajax Configuration</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/sean_howell/sharepoint_asp_net_ajax_configuration.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1707</id>

    <published>2010-02-02T23:34:17Z</published>
    <updated>2010-02-03T20:00:25Z</updated>

    <summary>In the world of web development, there is a little thing called ajax. Ajax is so simple because it is built in to Javascript. I like to use ajax to...</summary>
    <author>
        <name>Sean Howell</name>
        
    </author>
    
        <category term=".NET" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Web Development" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[In the world of web development, there is a little thing called ajax. Ajax is so simple because it is built in to Javascript. I like to use ajax to make web applications that look like they are not stuck in the past. Tools like jQuery make ajax so simple with its commands like:<div><pre class="prettyprint">$.get $.post $.load</pre>ASP .Net has, what they tout as ultra simple, the update panel for ajax post backs to the server. But, this tool is not as simple as it seems. While deceptively simple to stick on a page and wire up to the code behind, it takes much more to make this tool work.<div><br /><div>Like everything else in the Microsoft world, to make ASP .Net have ajax requires a dll and, through reading the documentation, a crap load of changes to the web.config file. Sure, it is easy to get the web.config all nice and set up if you have Visual Studios do it for you. Just create a new Web Site and start debugging the website. Voila, all of the configuration setting needed to use ajax are there.<br /></div><div><br /></div><div>But, for those whose have to do through code for, say, a Sharepoint web site that has to be deployed anywhere, they feel the pain of drudging through the required assembly strings and making SPWebConfigModifications. So, the first step on the path to Sharepoint ajaxiness is to go out to all the dlls and collect all the assembly strings needed:</div><div><br /><pre class="prettyprint">const string scriptResourceHandler = "System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
const string scripthandlerfactory = "ScriptHandlerFactory";
const string scripthandlerfactoryappservice = "ScriptHandlerFactoryAppService";
const string scriptresource = "ScriptResource";
const string scriptModuleAssembly = "System.Web.Handlers.ScriptModule,System.Web.Extensions,Version=3.5.0.0,Culture=Neutral,PublicKeyToken=31bf3856ad364e35";
const string webScriptAssembly = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35";
const string webExtensionAssembly = "System.Web.Extensions,Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</pre>After you have done that, or just copied the above assemblies, those assemblies have to be added to the web.config. That is where the SPWebConfigModification comes into play. First, you'll want to clear the modifications otherwise, modifications might appear for items that are long gone.&nbsp;</div><div><br /><pre class="prettyprint">webApp.WebConfigModifications.Clear();</pre>After that is set up, there is quite a bit to add to the WebConfigModification collection. Here OWNER, is something you set somewhere else and keep handy for when you have to remove all of the changes from the web.config.</div><div><br /><pre class="prettyprint">webApp.WebConfigModifications.Add(CreateControlSection());		webApp.WebConfigModifications.Add(CreateSafeControl(webExtensionAssembly,"System.Web.UI"));
webApp.WebConfigModifications.Add(CreateAjaxAssembly(webExtensionAssembly));			webApp.WebConfigModifications.Add(CreateHttpScriptHandler(scriptModuleAssembly,"ScriptModule"));
webApp.WebConfigModifications.Add(CreateScriptResource(scriptResourceHandler,"ScriptResource.axd","GET,HEAD"))
webApp.WebConfigModifications.Add(CreateScriptResource(webScriptAssembly,"*_AppService.axd","*"));
webApp.WebConfigModifications.Add(CreateScriptResource(webScriptAssembly,"*.asmx","*"));
webApp.WebConfigModifications.Add(CreateWebServerSection());
webApp.WebConfigModifications.Add(CreateWebServerHandlerSection());
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scripthandlerfactory));
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scripthandlerfactoryappservice));
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scriptresource));
webApp.WebConfigModifications.Add(CreateWebServiceHandler(webScriptAssembly,"*.asmx","*",scripthandlerfactory));
webApp.WebConfigModifications.Add(CreateWebServiceHandler(webScriptAssembly,"*_AppService.axd","*",scripthandlerfactoryappservice));webApp.WebConfigModifications.Add(CreateWebServiceHandler(scriptResourceHandler,"ScriptResource.axd", "GET,HEAD", scriptresource));
webApp.Farm.Services.GetValue<spwebservice>().ApplyWebConfigModifications();
webApp.Update();
/* Thus begins the many methods to add each little piece of the web.config */
private SPWebConfigModification CreateScriptResource(string assembly,string path,string verb) {
      return new SPWebConfigModification {
		Path = "configuration/system.web/httpHandlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@verb='{2}'][@path='{1}'][@type='{0}'][@validate='false']",assembly,path,verb),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add verb="{2}" path="{1}" type="{0}" validate="false">", assembly,path,verb)
	};
}

private SPWebConfigModification CreateWebServiceHandler(string assembly,string path,string verb,string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.webServer/handlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@verb='{2}'][@path='{1}'][@type='{0}'][@preCondition='integratedMode'][@name='{3}']",assembly,path,verb,name),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add verb="{2}" path="{1}" type="{0}" precondition="integratedMode" name="{3}">", assembly,path,verb,name)
	};
}
private SPWebConfigModification RemoveWebServiceHandler(string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.webServer/handlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@name='{0}']",name),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<remove name="{0}">",name)
	};
}

private static SPWebConfigModification CreateHttpScriptHandler(string assembly,string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.web/httpModules",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@name='{0}'] [@type='{1}']",name, assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add name="{0}" type="{1}">",name, assembly)
	};
}

private static SPWebConfigModification CreateAssembly(string assembly) {
	return new SPWebConfigModification {
	        Path = "configuration/system.web/compilation/assemblies",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@assembly='{0}']", assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<add assembly="{0}">", assembly)
	};
}
private static SPWebConfigModification CreateAjaxAssembly(string assembly) {
	return new SPWebConfigModification {
		Path = "configuration/system.web/pages/controls",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@tagPrefix='{0}'][@namespace='{1}'][@assembly='{2}']","asp","System.Web.UI", assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<add tagprefix="{0}" namespace="{1}" assembly="{2}">","asp","System.Web.UI", assembly)
	};
}
private static SPWebConfigModification CreateSafeControl(string assembly, string nameSpace) {
	return new SPWebConfigModification {
		Path = "configuration/SharePoint/SafeControls",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "SafeControl[@Assembly='{0}'][@Namespace='{1}'][@TypeName='*'][@Safe='True']", assembly, nameSpace),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<safecontrol assembly="{0}" namespace="{1}" typename="*" safe="True">", assembly,				nameSpace)
	};
}
private static SPWebConfigModification CreateControlSection() {
	return new SPWebConfigModification {
		Path = "configuration/system.web/pages",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "controls",
		Value =@"<controls></controls>",
		Sequence = 0,
		Owner = OWNER
	};
}
private static SPWebConfigModification CreateWebServerSection() {
	return new SPWebConfigModification {
		Path = "configuration",
	        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "system.webServer",
		Value =@"<system.webserver></system.webserver>",
		Sequence = 0,
		Owner = OWNER
	};
}
private static SPWebConfigModification CreateWebServerHandlerSection() {
       return new SPWebConfigModification {
		Path = "configuration/system.webServer",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "handlers",
		Value =@"<handlers></handlers>",
		Sequence = 0,
		Owner = OWNER
	};		
}</safecontrol></add></add></add></remove></add></add></spwebservice></pre><br />So, why on earth does it take that much code to generate the xml required to use ajax in Sharepoint?</div></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>Hello, World!</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/andrew_wagner/hello_world.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1705</id>

    <published>2010-01-31T22:01:49Z</published>
    <updated>2010-01-31T22:04:35Z</updated>

    <summary>I&apos;m a new software engineer here at Near Infinity, and very excited to be aboard! Hope to put some real content on this blog soon....</summary>
    <author>
        <name>Andrew Wagner</name>
        
    </author>
    
    <category term="meta" label="meta" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        I&apos;m a new software engineer here at Near Infinity, and very excited to be aboard! Hope to put some real content on this blog soon. 
        
    </content>
</entry>

<entry>
    <title>Using Keynote Remote When There&apos;s No Wi-Fi Around</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/scott_leberknight/using_keynote_remote_when_ther.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1704</id>

    <published>2010-01-25T04:14:35Z</published>
    <updated>2010-01-25T04:17:31Z</updated>

    <summary> I just bought Keynote Remote for my iPhone. It is very simple, has the option to display presenter notes, and is absurdly simple to link to Keynote and start...</summary>
    <author>
        <name>Scott Leberknight</name>
        
    </author>
    
        <category term="iPhone" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="iphone" label="iphone" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="keynote" label="keynote" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[ <p>I just bought <a href="http://appadvice.com/appnn/2009/01/review-keynote-remote/">Keynote Remote</a> for my iPhone. It is very simple, has the option to display presenter notes, and is absurdly simple to link to Keynote and start controlling presentations. What was a little more involved was that I wanted to use it regardless of whether there is a wireless network around or not. Since Keynote Remote requires a wi-fi connection here's what I'm doing to get around this little annoyance. Basically all you need to do is set up an ad-hoc wireless network with your Mac, and have your iPhone connect to that network. Voila! So, when there's no wireless network available, I just use my handy-dandy Verizon Wireless USB760 Modem to connect to the Internet, and I can still control presentations with Keynote Remote.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Low Memory Patch For Lucene</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/aaron_mccurry/low_memory_patch_for_lucene.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1703</id>

    <published>2010-01-20T02:25:35Z</published>
    <updated>2010-01-20T02:44:51Z</updated>

    <summary><![CDATA[While I'm working on getting my code into lucene. &nbsp;I have patched 3.0.0 and 2.9.1 with my low memory patch.By default the small memory footprint is enabled to change back...]]></summary>
    <author>
        <name>Aaron McCurry</name>
        
    </author>
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Lucene" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[While I'm working on getting my code into lucene. &nbsp;I have patched 3.0.0 and 2.9.1 with my <a href="http://www.nearinfinity.com/blogs/aaron_mccurry/my_first_lucene_patch.html">low memory patch</a>.<div><br /></div><div>By default the small memory footprint is enabled to change back to the default implementation set the following system property.</div><div><br /></div><div>-Dorg.apache.lucene.index.TermInfosReader=default<div><br /></div><div>Have fun! &nbsp;If you have any problems or questions please let me know or add to this <a href="https://issues.apache.org/jira/browse/LUCENE-2205">LUCENE-2205</a>.</div><div><br /></div><div><a href="http://www.nearinfinity.com/blogs/assets/amccurry/lucene-core-3.0.0-nic.jar">lucene-core-3.0.0-nic.jar</a></div><div><br /></div><div><a href="http://www.nearinfinity.com/blogs/assets/amccurry/lucene-core-2.9.1-nic.jar">lucene-core-2.9.1-nic.jar</a></div><div><br /></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>Lucene Hit Paging Made Easier</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/aaron_mccurry/making_lucene_hit_results_pagi.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1702</id>

    <published>2010-01-18T21:16:59Z</published>
    <updated>2010-01-19T01:43:27Z</updated>

    <summary><![CDATA[Lucene gives users the ability to search massive amounts of data in a very short amount of time. &nbsp;However allowing users to page through the entire result set of their...]]></summary>
    <author>
        <name>Aaron McCurry</name>
        
    </author>
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Lucene" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[Lucene gives users the ability to search massive amounts of data in a very short amount of time. &nbsp;However allowing users to page through the entire result set of their search can be difficult and risky depending on how many users are performing searches and how many of those users are paging through 100's if not 1,000's of hits per page.<div><br /></div><div>Problem Scenario:</div><div><br /></div><div><ul><li>Each of your indexes contains 100,000,000's documents.</li><li>You have 500 users on your system&nbsp;actively&nbsp;performing searches.</li><li>You have 100 search results per page.</li><li>And, your typical user pages through the first 10 pages of results. &nbsp;(Normal&nbsp;occurrence&nbsp;on some systems)</li></ul></div><div><br /></div><div>So for the 10th page you will have to collect 1,000 hits, at a cost of a float plus an int plus some object overhead per hit. &nbsp;So let's say 20 bytes per hit. &nbsp;So you have 500 users * 1,000 hits * 20 bytes = 1,000,000 bytes or 1M. &nbsp;Easy, no problem, right?</div><div><br /></div><div>Well what if you also give the users an easy way to move to the end of the result set. &nbsp;Hmm... &nbsp;Well for a result set size of 10,000 it's no big deal. &nbsp;But what if you hand out result sets in the order of a 1,000,000 or even 10,000,000.</div><div><br /></div><div>At this point you really just want to prevent the system from running out of memory. &nbsp;Because if you have 25 users getting 10,000,000 results each and they all click last page at the same time. &nbsp;That's going to cost you 5 Gig of heap! &nbsp;At least. &nbsp;Some might say that it won't ever happen, but in my experience, if it can happen, it will.</div><div><br /></div><div>So I created a Paging Hit Collector, that windows the hits to the users. &nbsp;It's uses the last hit collected from the previous search pass, to feed the next search pass. &nbsp;So yes if a user clicks the last page, it might perform multiple searches but, the system won't run out of memory.</div><div><br /></div><div>The user's will get there answer&nbsp;eventually, and if your system gives them some feedback as it searches and pages, they will probably sit and wait for it to come back. &nbsp;Instead of giving up and hitting cancel and search and cancel and search, and making the system worse and worse.</div><div><br /></div><b>

The Simple Example:</b><div><b><br /></b><div><div>
<pre class="prettyprint">IndexSearcher searcher = new IndexSearcher(reader);<br />
TermQuery query = new TermQuery(new Term("f1", "value"));
IterablePaging paging = new IterablePaging(searcher, query, 100);<br />
for (ScoreDoc sd : paging.skipTo(90)) {
&nbsp;&nbsp;System.out.println("doc id [" + sd.doc + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"score [" + sd.score + "]");
}
</pre>
</div></div><b><div><b><br /></b></div>

The More Advanced Example:</b></div><div><b><br /></b><div><div>
<pre class="prettyprint">IndexSearcher searcher = new IndexSearcher(reader);<br />
TotalHitsRef totalHitsRef = new TotalHitsRef();
ProgressRef progressRef = new ProgressRef();<br />
TermQuery query = new TermQuery(new Term("f1", "value"));
IterablePaging paging = new IterablePaging(searcher, query, 100);<br />
for (ScoreDoc sd : paging.skipTo(90).
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gather(20).
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalHits(totalHitsRef).
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;progress(progressRef)) {<br />
&nbsp;&nbsp;System.out.println("time [" + progressRef.queryTime() + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"total hits [" + totalHitsRef.totalHits() + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"searches [" + progressRef.searchesPerformed() + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"position [" + progressRef.currentHitPosition() + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"doc id [" + sd.doc + "] " + 
&nbsp;&nbsp;&nbsp;&nbsp;"score [" + sd.score + "]");
}
</pre>
</div></div><div><br /></div><div>Here's a link to the code <a href="https://issues.apache.org/jira/browse/LUCENE-2215">LUCENE-2215</a>.</div><div><br /></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>My First Lucene Patch - Making Lucene Do More With Less</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/aaron_mccurry/my_first_lucene_patch.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1699</id>

    <published>2010-01-12T01:06:21Z</published>
    <updated>2010-01-13T08:31:01Z</updated>

    <summary><![CDATA[I've been using Lucene for the better part of 2 years, from initial playing around, to prototyping to production application. &nbsp;It's an impressive library and it has come along way...]]></summary>
    <author>
        <name>Aaron McCurry</name>
        
    </author>
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Lucene" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[I've been using Lucene for the better part of 2 years, from initial playing around, to prototyping to production application. &nbsp;It's an impressive library and it has come along way in the past couple of years.<div><br /></div><div>When I first started playing around with it the version was 2.1 and the search times were so much faster than what we were trying to use at the time (Oracle Text). &nbsp;The first test was indexing a monster dataset and searching it quickly. &nbsp;It passed with flying colors!</div><div><br /></div><div>Next was to add in record level access control. &nbsp;<a href="http://java.dzone.com/articles/how-implement-row-level-access">Easy</a>&nbsp;and extremely fast.</div><div><br /></div><div>Next was to add in all the other data needed for our application. &nbsp;That was a little bit harder, considering that we have close to 150 fields in our index and well into the billion record range (growing everyday).</div><div><br /></div><div>The problem was that we needed more memory and there was no extra money for any more servers (or upgrades). &nbsp;So there we were, stuck. &nbsp;So I decided to start poking around using <a href="https://visualvm.dev.java.net/">visualvm</a>&nbsp;to see if there were any places in our application or in Lucene to save some memory.</div><div><br /></div><div>We had already disabled norms on all our fields (we really didn't need norms for our data nor did we have the resources). &nbsp;Took a long look at all our fields that we were indexing to see if there were any we didn't need, but we really did need them all. &nbsp;Then I stumbled across the TermInfosReader class in Lucene.</div><div><br /></div><div>This is where Lucene really gets it speed, but also uses quite a bit memory to do it. &nbsp;And this is where I wrote my first Lucene patch.</div><div><br /></div><div>In TermInfosReader there is a bunch stuff but the big memory hogs are in three arrays.</div><div><br /></div><div><ul><li>Terms[]</li><li>TermInfos[]</li><li>long[]</li></ul></div><div>Basically Lucene does a binary search across the Terms array (that by default contains every 128th Term in the index) with a given Term to find where on disk the exact Term needed lives. &nbsp;There's a little bit more going on in the class than that, but that's basically what it's doing.</div><div><br /></div><div>So, I started this patch with the need to save memory. &nbsp;So how in the world do you do that in java when everything is already in basic arrays and everything is needed in memory. &nbsp;Well you have to save it another way, references. &nbsp;References are a hidden cost in Java, every single reference in 32-bit JVM costs you 4 bytes, and 64-bit JVM it's 8 (assuming that you don't have compressed references).</div><div><br /></div><div>Let's count the references.</div><div><br /></div><div><ul><li>Terms[] length * 3, 1 reference for the Term and 2 references for the two Strings inside the Term</li><li>TermInfo[] length * 1</li><li>long[] = 1 reference total<br /></li></ul><div>So, let's talk numbers. &nbsp;If you have a billion terms in your index, that's 125 MB (1,000,000,000 / 128 * (3 + 1 references) * 4 bytes for every ref) bytes of memory for the references. &nbsp;In a 64-bit JVM that doubled 250 MB. &nbsp;Not to mention the object overhead for every one of those Term and TermInfos objects. Wow that's a lot!</div><div><br /></div><div>So I decided to remove nearly all of those references by using a byte array and an int array as an offset index.</div><div><br /></div><div>The results were impressive!</div><div><br /></div><div>Given an index of 6.2 GB size 1,010,000&nbsp;number of documents with 179,822,683 number of terms the default implementation uses 292,235,512 bytes to just get the index usable.</div><div><br /></div><div>My no-ref implementation of the same index uses only 49,849,744 bytes get the index usable. &nbsp;That a 17% of the original size, that's an 83% savings!</div><div><br /></div><div>And the best part is, that it loads the segments faster into memory. &nbsp;So those real-time updates will be online faster. &nbsp;The run-time performance is slightly faster as well. &nbsp;But the huge performance saving is in garbage collection. &nbsp;Over 7 times faster for full GC's on my Macbook Pro. &nbsp;Wow!</div><div><br /></div><div>I think that the results speak for themselves, and I hope that the Lucene folks will accept my patch. &nbsp;That way I won't have to continue patching each version after the fact. &nbsp;Also removing references can be great, but the code required to do it, and maintain the same level of performance, is ugly! &nbsp;So don't try this at home!</div><div><br /></div><div><a href="https://issues.apache.org/jira/browse/LUCENE-2205">LUCENE-2205</a></div><div><br /></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>Using HBase-dsl</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/aaron_mccurry/using_hbase-dsl.html" />
    <id>tag:www.nearinfinity.com,2010:/blogs//7.1698</id>

    <published>2010-01-06T03:34:20Z</published>
    <updated>2010-01-12T19:39:25Z</updated>

    <summary><![CDATA[At the beginning of last month I started prototyping various solutions for a customer using HBase. &nbsp;However I found myself writing tons of code to perform some fairly simple tasks....]]></summary>
    <author>
        <name>Aaron McCurry</name>
        
    </author>
    
        <category term="Database" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Hadoop" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Persistence" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="hadoop" label="hadoop" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="hbase" label="hbase" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="hbasedsl" label="hbase-dsl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[At the beginning of last month I started prototyping various solutions for a customer using HBase. &nbsp;However I found myself writing tons of code to perform some fairly simple tasks. &nbsp;So I set out to simply my HBase code and ended up writing a Java <a href="http://wiki.github.com/nearinfinity/hbase-dsl" target="_blank">HBase DSL</a>. &nbsp;It's still fairly rough around the edges but it does allow the use of standard Java types and it's extensible.<div><br /><font class="Apple-style-span" style="font-size: 1.25em; "><font class="Apple-style-span" style="font-size: 1.25em; ">

Simple Put and Get Example</font></font><br /><br /><b>

Direct HBase API:</b><br />

<br />
<pre class="prettyprint">public class PutAndGet {
   public static void main(String[] args) throws IOException {
      HTable hTable = new HTable("test");

      byte[] rowId = Bytes.toBytes("abcd");
      byte[] famA = Bytes.toBytes("famA");
      byte[] col1 = Bytes.toBytes("col1");
      Put put = new Put(rowId).
         add(famA, col1, Bytes.toBytes("hello world!"));
      hTable.put(put);
      Get get = new Get(rowId);
      Result result = hTable.get(get);
      byte[] value = result.getValue(famA, col1);
      System.out.println(Bytes.toString(value));
   }
}
</pre><b>HBase-dsl API:</b><br /><br />
<pre class="prettyprint">public class PutAndGetWithDsl { 
   public static void main(String[] args) throws IOException { 
      HBase&lt;QueryOps, String&gt; hBase = new HBase&lt;QueryOps&lt;String&gt;, String&gt;(String.class);

      hBase.save("test").  
         row("abcd"). 
            family("famA"). 
               col("col1", "hello world!"); 
      String value = hBase.fetch("test"). 
         row("abcd").
            family("famA"). 
               value("col1", String.class)
      System.out.println(value);
   }
 }</pre>

Now this is where the dsl becomes more powerful!<div><br /><font class="Apple-style-span" style="font-size: 1.25em; "><font class="Apple-style-span" style="font-size: 1.25em; ">

Scanner Example</font></font><br /><br /><b>

Direct HBase API:</b><br /><br />

<pre class="prettyprint">public class Scanner {
   public static void main(String[] args) throws IOException {
      byte[] famA = Bytes.toBytes("famA");
      byte[] col1 = Bytes.toBytes("col1");  

      HTable hTable = new HTable("test");  

      Scan scan = new Scan(Bytes.toBytes("a"), Bytes.toBytes("z"));
      scan.addColumn(famA, col1);  

      SingleColumnValueFilter singleColumnValueFilterA = new SingleColumnValueFilter(
           famA, col1, CompareOp.EQUAL, Bytes.toBytes("hello world!"));
      singleColumnValueFilterA.setFilterIfMissing(true);  

      SingleColumnValueFilter singleColumnValueFilterB = new SingleColumnValueFilter(
           famA, col1, CompareOp.EQUAL, Bytes.toBytes("hello hbase!"));
      singleColumnValueFilterB.setFilterIfMissing(true);  

      FilterList filter = new FilterList(Operator.MUST_PASS_ONE, Arrays
           .asList((Filter) singleColumnValueFilterA,
                singleColumnValueFilterB));  

      scan.setFilter(filter);  

      ResultScanner scanner = hTable.getScanner(scan);  

      for (Result result : scanner) {
         System.out.println(Bytes.toString(result.getValue(famA, col1)));
      }
   }
}</pre>
<b>HBase-dsl API:</b><br /><br />

<pre class="prettyprint">public class ScannerWithDsl {
   public static void main(String[] args) throws IOException {
      HBase&lt;QueryOps, String&gt; hBase = new HBase&lt;QueryOps&lt;String&gt;, String&gt;(String.class);

      hBase.scan("test","a","z").
         select().
            family("famA").
               col("col1").
         where().
            family("famA").
               col("col1").eq("hello world!","hello hbase!").
         foreach(new ForEach<row>() {
            @Override
            public void process(Row row) {
               System.out.println(row.value("famA", "col1", String.class));
            }
         });
  }
}</row></pre><br />
See the unit tests, for more examples.<br /><br /></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>Business Process Modeling for Software Developers</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/lee_richardson/business_process_modeling_for.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1697</id>

    <published>2009-12-23T14:01:57Z</published>
    <updated>2009-12-23T14:13:26Z</updated>

    <summary>As a software developer I never thought I&apos;d be saying this (I suppose eight years of working for the company that invented this technique might bias me), but you can...</summary>
    <author>
        <name>Lee Richardson</name>
        
    </author>
    
        <category term="Agile Development" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="agile" label="agile" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="process" label="process" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[<p>As a software developer I never thought I'd be saying this (I suppose eight years of working for the company that invented this technique might bias me), but you can not underestimate the value of business process modeling when starting a new project.  This is especially true if it's a small project and you don't have the benefit of a dedicated requirements analyst.</p>

<div style='float:right; margin-left:10px;'>
<script type='text/javascript'>
        var currentPageUrl = 'http://rapidapplicationdevelopment.blogspot.com/2009/12/business-process-modeling-for-software.html';
 
        /* Digg */
        var diggIframe = document.createElement('iframe');
        diggIframe.setAttribute('src', 'http://digg.com/tools/diggthis.php?u=' + currentPageUrl);
        diggIframe.setAttribute('height', '80');
        diggIframe.setAttribute('width', '52');
        diggIframe.setAttribute('frameborder', '0');
        diggIframe.setAttribute('scrolling', 'no');
        diggIframe.setAttribute('style', 'margin-left:auto; margin-right:auto; display:block; text-align:center;');
 
        /* DotNetKicks */
        var dotnetkicksLink = document.createElement('a');
        dotnetkicksLink.setAttribute('href', 'http://www.dotnetkicks.com/kick/?url=' + currentPageUrl);
        var dotnetkicksImg = document.createElement('img');
        dotnetkicksImg.setAttribute('src', 'http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=' + currentPageUrl);
        dotnetkicksImg.setAttribute('alt', 'Kick this article (a good thing) on DotNetKicks');
        dotnetkicksImg.setAttribute('border', '0');
        dotnetkicksImg.setAttribute('style', 'margin-left:auto; margin-right:auto; display:block; text-align:center;');
        dotnetkicksLink.appendChild(dotnetkicksImg);
 
        var div = document.createElement('div');
        div.appendChild(dotnetkicksLink);
        div.appendChild(document.createElement('br'));
        div.appendChild(diggIframe);
 
        document.write(div.innerHTML);
    </script>
</div>

<p>As a consultant (or as a person who is learning someone else's business) your job is to understand your customers existing business <i>better than they do themselves</i>.  And you need to be on the same page with others regarding how you are going to change their day to day functions.  And that's what business process modeling is for.</p>

<p>You may ignore this document after the first week on the project, in fact I would encourage you to. But even if you throw it away immediately after creating it, the process of developing the document will still:</p>

<ul>
<li>Flush out important questions</li>
<li>Show your customer you understand their world</li>
<li>Help document the project to other developers</li>
<li>Facilitate communication (especially with the people who pay the bills)</li>
<li>Generate user stories (requirements) </li>
<li>Identify the entities that can feed into an <a href="http://rapidapplicationdevelopment.blogspot.com/2007/06/entity-relationship-diagram-example.html">Entity Relationship Diagram</a> (or database I suppose)</li>
<li>Aid making good choices for the decisions it be hard to undo later (like whether to manually code workflows or use <a href="http://en.wikipedia.org/wiki/Windows_Workflow_Foundation">Windows Workflow Foundation</a>)</li>
<li>More clearly identify pain points and areas where your software can help end users; and</li>
<li>Identify metrics that can help determine project success from an ROI and product owner's perspective</li>
</ul>

<p>Convinced this is a tool you need in your toolbelt yet?  As long as the answer isn't "I only write code leave me alone" then check out this quick how-to:</p>

<p><b>Start with the AS-IS diagram</b></p>

<p>As soon as possible on a new project you should plan to interview your future end users.  This shouldn't be an unstructured Q&amp;A session.  You should start with a rough draft of what you think their business process is and ask questions that identify the places where you were wrong.<p>

<p>In order to start the diagram you need to identify both the end users and existing systems and put those in "swimlanes" down the left side of a diagram.  Swimlanes are important because they help you be explicit about who is performing what activities.  Then flush out activities in the happy path in appropriate swimlanes like so:</p>
 
<p><a href="http://3.bp.blogspot.com/_gez10dNhuPk/SzISYvjEwvI/AAAAAAAABrg/8X9h_xxiDvw/s1600-h/AS-IS.gif"><img style="cursor:pointer; cursor:hand;width: 400px; height: 344px;" src="http://3.bp.blogspot.com/_gez10dNhuPk/SzISYvjEwvI/AAAAAAAABrg/8X9h_xxiDvw/s400/AS-IS.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5418413517969867506" /></a></p>
 
<p>As soon as you talk to end users (like the clerk in the example above) you will discover unhappy paths.  What if the warehouse is out of a product?  What if the payment was declined?  What happens if a customer needs to return something?</p>

<p>Obviously you document these using standard activity diagram notation:</p>

<p><a href="http://2.bp.blogspot.com/_gez10dNhuPk/SzISZP5NmgI/AAAAAAAABro/Q6AeYSTx7eo/s1600-h/Choice.gif"><img style="cursor:pointer; cursor:hand;width: 389px; height: 400px;" src="http://2.bp.blogspot.com/_gez10dNhuPk/SzISZP5NmgI/AAAAAAAABro/Q6AeYSTx7eo/s400/Choice.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5418413526652656130" /></a></p>

<p><b>Identifying Pain Points/Opportunities</b></p>
<p>The interesting part about unhappy paths is how often they occur, how they affect the customers of your customer, and ultimately how they affect your customer's bottom line.  For instance, how often is payment declined in the example above?  Fairly frequently?  Can you get an actual percentage?  If it turns out it's because the original application failed to validate credit cards, then a small amount of programming effort can provide a large benefit to length of time until order fulfillment.  Sometimes you can make the process more efficient without writing a line of code.</p>

<p>And at the end of your project if you can show that you've decreased the average length of time it takes to go through the process, ideally by showing less time was spent in unhappy paths, you will likely have made yourself one happy customer.  This can be especially effective if your new system can show statistics (like percent of orders that are declined) and compare those to the old process.</p>
<p><b>Developing the TO-BE diagram</b></p>
<p>AS-IS process diagrams are completely useless unless you can effectively describe what the process will look like after you implement your new system.  The process of developing these documents is pretty similar to the AS-IS diagram except of course you're trying to fix the pain points.</p>

<p>One technique I like for generating a backlog of user stories (tasks) is to put unique numbers with each step in the TO-BE process, then ensure there is at least one user story per step in the process.  You may be surprised at how easily activities in your new project's swimlane map to user stories.</p>
<p><b>Summary</b></p>
<p>I'm a fan of writing code as soon as possible on a project, but if you fail to understand an end user's business process you may be writing the wrong code.  Business process modeling can ensure you're writing the right code to solve the most important problems first.  And that may be the difference between project success and project failure.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Hibernate Performance Tuning Part 2 Article Published</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/scott_leberknight/hibernate_performance_tuning_p_1.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1695</id>

    <published>2009-12-21T19:17:55Z</published>
    <updated>2009-12-21T19:23:02Z</updated>

    <summary> I&apos;ve just published the second article of a two-part series in the December 2009 NFJS Magazine on Hibernate Performance Tuning. Here&apos;s the abstract: Tuning performance in Hibernate applications is...</summary>
    <author>
        <name>Scott Leberknight</name>
        
    </author>
    
        <category term="Database" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="ORM" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Persistence" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="hibernate" label="hibernate" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orm" label="ORM" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="performance" label="performance" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[  <p>I've just published the second article of a two-part series in the December 2009 <a href="http://www.nofluffjuststuff.com/home/magazine_subscribe?id=10">NFJS Magazine</a> on Hibernate Performance Tuning. Here's the abstract:</p>

<p><em>Tuning performance in Hibernate applications is all about reducing the number of database queries or eliminating them entirely using caching. In the first article in this two part series, you saw how to tune object retrieval using eager fetching techniques to optimize queries and avoid lazy-loads. In this second and final article, I'll show you how inheritance strategy affects performance, how to eliminate queries using the Hibernate second-level cache, and show some simple but effective tools you can use to monitor and profile your applications.</em></p>

<p>If you are using Hibernate and want to know more about how inheritance affects performance, how to use the second-level cache, and some simple monitoring and profiling techniques, check it out and let me know what you think. Note that NFJS Magazine does require a subscription.</p>]]>
        
    </content>
</entry>

<entry>
    <title>How to switch your Adobe Creative Suite from a PC to a Mac Platform</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/caroline_wizeman/how_to_switch_your_adobe_creat.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1694</id>

    <published>2009-12-18T20:33:37Z</published>
    <updated>2009-12-18T20:52:10Z</updated>

    <summary>I was considering switching from PC to a Mac, but I have Adobe CS4 Design Premium and didn&apos;t want to pay the $1,799 to buy it again. It was surprisingly...</summary>
    <author>
        <name>Caroline Wizeman</name>
        
    </author>
    
    <category term="adobephotoshopillustratorindesignmacpc" label="Adobe Photoshop Illustrator InDesign Mac PC" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[I was considering switching from PC to a Mac, but I have Adobe CS4 Design Premium and didn't want to pay the $1,799 to buy it again. It was surprisingly difficult to find any information about whether or not I could do it, and if so how. Some Adobe employees at a trade show even told me that it couldn't be done.<br /><br />It turns out, though, that for $6.25 shipping and handling and the promise that you'll stop using and destroy your older version, they'll let you change. They call it Cross-Platform Swap. Here's how you do it:<br /><br /><ol><li>Go to <a href="http://www.adobe.com/go/supportportal">http://www.adobe.com/go/supportportal</a> If you have an account, log in. If you don't, you'll need to create one.<br /><br /></li><li>Under Get Support, Click on Orders and Returns<br /><br /></li><li>Choose the issue type Return / Exchange / Refund and then click the button that says Proceed to Online Form<br /><br /></li><li>Fill out the form, typing Cross Platform Swap in the subject line. Submit.<br />-- In the notes field, here's what I typed: <i>I am switching to a Mac and would like to do a cross-platform swap. I understand that my existing copy must be destroyed as soon as the new one arrives.</i><br /><br /></li><li>The next day, you'll get an email saying your issue is resolved and providing no useful information. Instructions for what to do next are actually in the ticket itself, which you can get back to on the support portal. Here's what you do:<br />-- Call 1-800-833-6687 and follow the prompts to customer service (#2 then #4)<br />-- Have your case number and credit card ready<br />-- Give them your credit card info and verify all your contact information<br /></li></ol>And that's it. They charge your credit card for $6.25 shipping and handling. Your old serial number gets invalidated, you destroy the old copy, and they send you the new one.<br /><br />As a side note, here's a tip for getting customer service from Adobe: Instead of going to the support portal when you have a question, go to the pages on their website where they have prices and information about purchasing products. Almost immediately, you'll get a helpful person IMing you asking if they can help. These IM helpers are nowhere to be found (ironically) in the support section of their site.<br /><br />Oh, and their customer support phone numbers aren't that easy to find, so here they are:<br /><b>Adobe Customer Support:</b> 1-800-585-0774 option #4<br />or<br /><b>Adobe Customer Support: </b>1-800-833-6687 option #2 then option #4.<br />&nbsp;<br />Good luck platform-swappers!<br /><br />]]>
        
    </content>
</entry>

<entry>
    <title>Making Cobertura Reports Show Groovy Code with Maven</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/scott_leberknight/making_cobertura_reports_show.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1691</id>

    <published>2009-12-16T04:33:19Z</published>
    <updated>2009-12-16T04:46:41Z</updated>

    <summary> A recent project started out life as an all-Java project that used Maven as the build tool. Initially we used Atlassian Clover to measure unit test coverage. Clover is...</summary>
    <author>
        <name>Scott Leberknight</name>
        
    </author>
    
        <category term="Groovy" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Testing" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cobertura" label="cobertura" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="groovy" label="groovy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="maven" label="maven" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[ <p>A recent project started out life as an all-Java project that used Maven as the build tool. Initially we used <a href="http://www.atlassian.com/software/clover/">Atlassian Clover</a> to measure unit test coverage. Clover is a great product for Java code, but unfortunately it only works with Java code because it works at the Java source level. (This was the case as of Spring 2009, and I haven't checked since then.) As we started migrating existing code from Java to Groovy and writing new code in Groovy, we started to lose data about unit test coverage because Clover does not understand Groovy code. To remedy this problem we switched from Clover to <a href="http://cobertura.sourceforge.net/">Cobertura</a>, which instruments at the bytecode level and thus works with Groovy code. Theoretically it would also work with any JVM-based language but I'm not sure whether or not it could handle something like Clojure or not.</p>

<p>In any case, we only cared about Groovy so Cobertura was a good choice. With the <a href="http://mojo.codehaus.org/cobertura-maven-plugin/">Cobertura Maven</a> plugin we quickly found a problem, which was that even though the code coverage was running, the reports only showed coverage for Java code, not Groovy. This blog shows you how to display coverage on Groovy code  when using Maven and the Cobertura plugin. In other words, I'll show how to get Cobertura reports to link to the real Groovy source code in Maven, so you can navigate Cobertura reports as you normally would.</p>

<p>The core problem is pretty simple, though it took me a while to figure out how to fix it. Seems to be pretty standard in Maven: I know what I want to do, but finding out how to do it is the <i>really</i> hard part. The only thing you need to do is tell Maven about the Groovy source code and where it lives. The way I did this is to use the Codehaus <a href="http://mojo.codehaus.org/build-helper-maven-plugin/">build-helper-maven-plugin</a> which has an add-source goal. The add-source goal does just what you would expect; it adds a specified directory (or directories) as a source directory in your Maven build. Here's how you use it in your Maven pom.xml file:</p>

<pre class="prettyprint">
&lt;plugin&gt;
    &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
    &lt;artifactId&gt;build-helper-maven-plugin&lt;/artifactId&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;phase&gt;generate-sources&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;add-source&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;configuration&gt;
                &lt;sources&gt;
                    &lt;source&gt;src/main/groovy&lt;/source&gt;
                &lt;/sources&gt;
            &lt;/configuration&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</pre>

<p>In the above code snippet, we're  using the "build-helper-maven-plugin" to add the src/main/groovy directory. That's pretty much it. Run Cobertura as normal, view the reports, and you should now see coverage on Groovy source code as well as Java.</p>
]]>
        
    </content>
</entry>

<entry>
    <title>SharePoint Power User - Really?</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/karen_upton/sharepoint_power_user_-_really.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1690</id>

    <published>2009-12-11T01:14:42Z</published>
    <updated>2009-12-11T01:17:03Z</updated>

    <summary>Having just completed a week of SharePoint Power User training, one thing is evident -- I am far from being a Power User. What they should call the class is...</summary>
    <author>
        <name>Karen Upton</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[<span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: arial, sans-serif; border-collapse: collapse; "><p>Having just completed a week of SharePoint Power User training, one thing is evident -- I am far from being a Power User. What they should call the class is SharePoint User Tapas. Trainees get just a little taste of all that SharePoint can do. It's enough to make us say "Ooh, I love this," and "I'm not so crazy about that." I can certainly see the benefits of implementing SharePoint in an organization, and I also understand the dangers if it is not done well. This leads me to one conclusion -- don't be afraid to think big, but start small. Choose one business problem to focus on, make sure it's one you think you can get your organization to buy in to, and go from there. It is not very likely that SharePoint will be the best solution for every business problem that you have.</p><p class="MsoNormal" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">Training always leaves you with a head full ideas for how to implement solutions based on the new knowledge you have gained. It's like meeting a new love interest for the first time -- you think of all of the things that "could be," but you have to go on a lot of dates before you can sort out what is reality versus fantasy in terms of your expectations.</p></span> ]]>
        
    </content>
</entry>

<entry>
    <title>Hibernate Performance Tuning Part 1 Article Published</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/scott_leberknight/hibernate_performance_tuning_p.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1688</id>

    <published>2009-12-02T00:29:07Z</published>
    <updated>2009-12-02T00:39:47Z</updated>

    <summary> I&apos;ve just published an article in the November 2009 NFJS Magazine on Hibernate Performance Tuning. Here&apos;s the abstract: Many developers treat Hibernate like a &quot;black box&quot; and assume it...</summary>
    <author>
        <name>Scott Leberknight</name>
        
    </author>
    
        <category term="Database" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Java" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="ORM" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Persistence" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="hibernate" label="hibernate" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orm" label="ORM" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="performance" label="performance" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[ <p>I've just published an article in the November 2009 <a href="http://www.nofluffjuststuff.com/home/magazine_subscribe?id=9">NFJS Magazine</a> on Hibernate Performance Tuning. Here's the abstract:</p>

<p><em>Many developers treat Hibernate like a "black box" and assume it will simply "Do the Right Thing" when it comes to all things related to the underlying database. This is a faulty assumption because, while Hibernate is great at the mechanics of database interaction, it cannot and will likely not ever be able to figure out the specific details of your domain model and discern the most efficient and best performing data access strategies. In this first article of a two part series, I'll show you how to achieve better performance in your Hibernate applications by focusing on tuning object retrieval, which forms the basis of your "fetch plan" for finding and storing objects in the database.</em></p>

<p>If you are using Hibernate and want to know more about how to change how objects are fetched from the database, check it out and let me know what you think. Note that NFJS Magazine does require a subscription.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Be careful with Groovy&apos;s optional parens on method calls!</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/chris_rohr/becareful_with_groovys_optiona.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1685</id>

    <published>2009-11-18T21:20:17Z</published>
    <updated>2009-12-21T20:41:37Z</updated>

    <summary><![CDATA[My current project (a web application) has a module that is almost entirely written in Groovy.&nbsp; Note: We are using the latest version 1.6.5 of Groovy.In one of the methods...]]></summary>
    <author>
        <name>Chris Rohr</name>
        
    </author>
    
        <category term="Groovy" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="arraylist" label="ArrayList" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="groovy" label="groovy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ibm" label="ibm" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="jvm" label="jvm" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[<p>My current project (a web application) has a module that is almost entirely written in Groovy.&nbsp; <b>Note:</b> We are using the latest version 1.6.5 of Groovy.</p><p>In one of the methods we had some logic similar to the following:<br /><br /></p><code> def myMethodToProcessTheList(def listOfThings) {<br /></code><blockquote><code>if (listOfThings &amp;&amp; listOfThings.size &lt; 0) {<br />&nbsp;&nbsp;&nbsp; //Do my logic<br /></code><code>}<br /></code></blockquote><code>}</code><br /><br />When the above code is run using Java 5 everything works wonderfully.&nbsp; However when we pushed the code out to our server running Java 6 we got an interesting error stating that it couldn't compare java.util.ArrayList to java.lang.Integer.<br /><br />The problem is actually that the size method needs the parens after it (<b>Note:</b> The Groovy docs actually do state that methods with at least <u>ONE</u> param can omit the parens).&nbsp; I realize now that it would make sense that parameter-less methods would need parens because how else would Groovy distinguish between methods and property accessors?&nbsp; I did find one forum <a href="http://old.nabble.com/TestApp.groovy-pre-Grails-1.1-td22437010.html">post</a> that indicated that in Groovy, lists have special properties that act like the spread-dot operator.&nbsp; That is why the listOfThings.size returned the ArrayList instead of a number.<br /><br />So why does this work in Java 5 but not Java 6?&nbsp; That is a great question, one of which I really don't have a definitive answer.&nbsp; I'm not completely sure if this purely a Java 5/Java 6 difference or simply a difference between the IBM Java 5/Java 6 JVM.<br /><br />If anyone has a theory as to why it would work one way on Java 5 and the other in Java 6, I would love to hear it.<br /><code></code><blockquote><code></code></blockquote>]]>
        
    </content>
</entry>

<entry>
    <title>Protect your Rails Model Objects with Grant</title>
    <link rel="alternate" type="text/html" href="http://www.nearinfinity.com/blogs/jeff_kunkle/protect_your_rails_model_objec.html" />
    <id>tag:www.nearinfinity.com,2009:/blogs//7.1684</id>

    <published>2009-11-18T19:00:00Z</published>
    <updated>2009-11-18T16:47:37Z</updated>

    <summary>Near Infinity recently announced the release of Grant, a Ruby on Rails plugin for securing and auditing access to your Rails model objects, and I&apos;m here to tell you a...</summary>
    <author>
        <name>Jeff Kunkle</name>
        
    </author>
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.nearinfinity.com/blogs/">
        <![CDATA[<p>Near Infinity recently announced the release of <a href="http://github.com/nearinfinity/grant">Grant</a>, a Ruby on Rails plugin for securing and auditing access to your Rails model objects, and I'm here to tell you a little bit about it. There are two primary pieces of Grant, model security and model audit. I'll be focusing on model security for this post and will address model audit in a later entry.</p>

<p>Grant's model security is deliberately designed to force the developer to make conscious security decisions about what CRUD operations a user should be allowed to perform on your model objects. It doesn't care how you choose to authenticate and authorize your users to perform a CRUD operation, it only cares that you actually do it.</p>

<p>Rather than specify which operations are restricted, Grant restricts all CRUD operations unless they're explicitly granted to the user. It also restricts adding or removing items from <em>has_many</em> and <em>has_and_belongs_to_many</em> associations. Only allowing operations explicitly granted forces you to make conscious security decisions. While it obviously can't ensure you make the correct decisions, it should help ease the latent fear that you've inadvertently forgotten to secure something.</p>

<p>Enough talk, let me show you an example of how you might use it. To enable model security you simply include the Grant::ModelSecurity module in your model class. In this example you see three grant statements. The first grants find (aka read) permission to everyone. The second example grants create, update, and destroy permission when the passed block evaluates to true, which in this case happens when the model is editable by the current user. You can put any code you want in that block as long as it returns a boolean value. Similarly, the third grant statement permits additions and removals from the tags association when it's block evaluates to true. A Grant::ModelSecurityError is raised if any grant block evaluates to false or nil.</p>

<pre class="prettyprint">
class EditablePage < ActiveRecord::Base
  include Grant::ModelSecurity
  has_many :tags

  grant(:find) { true }
  grant(:create, :update, :destroy) do |user, model| 
    model.editable_by_user? user 
  end
  grant(:add => :tags, :remove => :tags) do |user, model, associated_model| 
    model.editable_by_user? user 
  end

  def editable_by_user? user
    user.administrator?
  end
end
</pre>

<p>There's a lot more to the grant statement than shown in the above example. For instance, you can have multiple grant statements for the same action. Ultimate permission to perform the action will not be granted unless all grant blocks evaluate to true.</p>

<p>As you can see, Grant is pretty simple to use, but it's not going to do the dirty work for you. It's up to you to make the proper security decisions. Grant's just there to make sure you don't forget. </p>
]]>
        

    </content>
</entry>

</feed>
