<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>ZoomInfo Blog</title>
	
	<link>http://www.zoominfo.com/business/blog</link>
	<description />
	<lastBuildDate>Wed, 16 May 2012 18:01:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/zoominfo/GpIR" /><feedburner:info uri="zoominfo/gpir" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
		<title>Non-traditional uses of Apache Hadoop</title>
		<link>http://www.zoominfo.com/business/blog/2012/05/non-traditional-uses-of-apache-hadoop/</link>
		<comments>http://www.zoominfo.com/business/blog/2012/05/non-traditional-uses-of-apache-hadoop/#comments</comments>
		<pubDate>Wed, 16 May 2012 18:01:13 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6341</guid>
		<description><![CDATA[The Apache Hadoop project develops open-source software for reliable, scalable,  distributed computing. The Hadoop framework allows for distributed processing of large data sets across clusters of computers using a simple programming model. It is designed to scale up from single &#8230; <a href="http://www.zoominfo.com/business/blog/2012/05/non-traditional-uses-of-apache-hadoop/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The Apache Hadoop project develops open-source software for reliable, scalable,  distributed computing. The Hadoop framework allows for distributed processing of large data sets across clusters of computers using a simple programming model. It is designed to scale up from single servers to thousands of machines, each offering local computation and storage. Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer, so delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures.</p>
<p>Since its initial release in late 2007, Hadoop has become the leading way to do Data Mining and Distributed Computing. The project enjoys support from major backers such as <a href="http://www.yahoo.com/">Yahoo!</a> and <a href="http://www.cloudera.com/">Cloudera</a> and a <a href="http://wiki.apache.org/hadoop/PoweredBy">very broad adoption rate</a> by both large and small companies. Right now, there are over <a href="http://www.indeed.com/jobs?q=hadoop&amp;l=">4100 Hadoop-related jobs posted on Indeed</a>. That’s 3x the number of Django jobs listed, and 5x more than the Node.js framework.</p>
<p>Here at Zoom, we employ Hadoop for a wide variety of data processing and data mining tasks. As one example, we’ve got 12 years of crawler data archived, comprising some 50 TB of information. That’s a fantastically rich corpus primed for data mining. This is what I’d refer to as a “traditional” use of Hadoop. That is, we store a massive amount of data in HDFS, and then run <a href="http://en.wikipedia.org/wiki/MapReduce">MapReduce</a> jobs against it, looking for interesting information. This use case is right in Hadoop’s sweet spot – if you bring the computation to where the data lives, you can achieve massive parallelism without worrying about things like network latency and network throughput.</p>
<p>But not all of our uses of Hadoop are so traditional. Given the variety of different data collection &amp; data processing tasks Zoom performs, not all of them lend themselves to a MapReduce model. For example, some of them query databases or Solr servers. Some make RESTful API requests to Google. Some run IMAP commands. Some crawl websites. But, in our opinion anyway, many of these use cases till lend themselves well to the Hadoop framework. What we generally end up doing is defining a work queue (eg: a crawl schedule) in HDFS, and store the results back into HDFS for use by other jobs.</p>
<p>Zoom isn’t in the business of building platforms, and you probably shouldn’t be either. It’s usually a much better use of resources to focus on your core competencies and do the things that make your company the best widget maker on the planet. Ready-made platforms generally reduce development costs and shrink time to market. And with today’s robust Open Source ecosystem, there are few reasons not to use off the shelf platforms like Hadoop. If you need a platform that’s:</p>
<ul>
<li>Horizontally and vertically scalable (ideally, with <a href="http://en.wikipedia.org/wiki/Process_isolation">process isolation</a>)</li>
<li>Fault-tolerant</li>
<li>Highly available</li>
<li>Complete with a simple reporting framework</li>
<li>Complete with a simple management/administration framework</li>
</ul>
<p>And you need it done quickly &amp; cheaply, Hadoop is definitely worth checking out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2012/05/non-traditional-uses-of-apache-hadoop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automating Solr tests using EmbeddedSolrServer</title>
		<link>http://www.zoominfo.com/business/blog/2012/04/automating-solr-tests-using-embeddedsolrserver/</link>
		<comments>http://www.zoominfo.com/business/blog/2012/04/automating-solr-tests-using-embeddedsolrserver/#comments</comments>
		<pubDate>Thu, 12 Apr 2012 18:40:53 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6336</guid>
		<description />
			<content:encoded><![CDATA[<style type="text/css"><!--
/**
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 */
.java5  {font-family:monospace;color: #006; border: 1px solid #d0d0d0; background-color: #f0f0f0;}
.java5 a:link {color: #000060;}
.java5 a:hover {background-color: #f0f000;}
.java5 .imp {font-weight: bold; color: red;}
.java5 .kw1 {color: #000000;  font-weight: bold;}
.java5 .kw2 {color: #000000; font-weight: bold;}
.java5 .kw3 {color: #006600; font-weight: bold;}
.java5 .kw4 {color: #006600; font-weight: bold;}
.java5 .kw5 {color: #003399; font-weight: bold;}
.java5 .kw6 {color: #003399; font-weight: bold;}
.java5 .kw7 {color: #003399; font-weight: bold;}
.java5 .kw8 {color: #003399; font-weight: bold;}
.java5 .kw9 {color: #003399; font-weight: bold;}
.java5 .kw10 {color: #003399; font-weight: bold;}
.java5 .kw11 {color: #003399; font-weight: bold;}
.java5 .kw12 {color: #003399; font-weight: bold;}
.java5 .kw13 {color: #003399; font-weight: bold;}
.java5 .kw14 {color: #003399; font-weight: bold;}
.java5 .kw15 {color: #003399; font-weight: bold;}
.java5 .kw16 {color: #003399; font-weight: bold;}
.java5 .kw17 {color: #003399; font-weight: bold;}
.java5 .kw18 {color: #003399; font-weight: bold;}
.java5 .kw19 {color: #003399; font-weight: bold;}
.java5 .kw20 {color: #003399; font-weight: bold;}
.java5 .kw21 {color: #003399; font-weight: bold;}
.java5 .kw22 {color: #003399; font-weight: bold;}
.java5 .kw23 {color: #003399; font-weight: bold;}
.java5 .kw24 {color: #003399; font-weight: bold;}
.java5 .kw25 {color: #003399; font-weight: bold;}
.java5 .kw26 {color: #003399; font-weight: bold;}
.java5 .kw27 {color: #003399; font-weight: bold;}
.java5 .kw28 {color: #003399; font-weight: bold;}
.java5 .kw29 {color: #003399; font-weight: bold;}
.java5 .kw30 {color: #003399; font-weight: bold;}
.java5 .kw31 {color: #003399; font-weight: bold;}
.java5 .kw32 {color: #003399; font-weight: bold;}
.java5 .kw33 {color: #003399; font-weight: bold;}
.java5 .kw34 {color: #003399; font-weight: bold;}
.java5 .kw35 {color: #003399; font-weight: bold;}
.java5 .kw36 {color: #003399; font-weight: bold;}
.java5 .kw37 {color: #003399; font-weight: bold;}
.java5 .kw38 {color: #003399; font-weight: bold;}
.java5 .kw39 {color: #003399; font-weight: bold;}
.java5 .kw40 {color: #003399; font-weight: bold;}
.java5 .kw41 {color: #003399; font-weight: bold;}
.java5 .kw42 {color: #003399; font-weight: bold;}
.java5 .kw43 {color: #003399; font-weight: bold;}
.java5 .kw44 {color: #003399; font-weight: bold;}
.java5 .kw45 {color: #003399; font-weight: bold;}
.java5 .kw46 {color: #003399; font-weight: bold;}
.java5 .kw47 {color: #003399; font-weight: bold;}
.java5 .kw48 {color: #003399; font-weight: bold;}
.java5 .kw49 {color: #003399; font-weight: bold;}
.java5 .kw50 {color: #003399; font-weight: bold;}
.java5 .kw51 {color: #003399; font-weight: bold;}
.java5 .kw52 {color: #003399; font-weight: bold;}
.java5 .kw53 {color: #003399; font-weight: bold;}
.java5 .kw54 {color: #003399; font-weight: bold;}
.java5 .kw55 {color: #003399; font-weight: bold;}
.java5 .kw56 {color: #003399; font-weight: bold;}
.java5 .kw57 {color: #003399; font-weight: bold;}
.java5 .kw58 {color: #003399; font-weight: bold;}
.java5 .kw59 {color: #003399; font-weight: bold;}
.java5 .kw60 {color: #003399; font-weight: bold;}
.java5 .kw61 {color: #003399; font-weight: bold;}
.java5 .kw62 {color: #003399; font-weight: bold;}
.java5 .kw63 {color: #003399; font-weight: bold;}
.java5 .kw64 {color: #003399; font-weight: bold;}
.java5 .kw65 {color: #003399; font-weight: bold;}
.java5 .kw66 {color: #003399; font-weight: bold;}
.java5 .kw67 {color: #003399; font-weight: bold;}
.java5 .kw68 {color: #003399; font-weight: bold;}
.java5 .kw69 {color: #003399; font-weight: bold;}
.java5 .kw70 {color: #003399; font-weight: bold;}
.java5 .kw71 {color: #003399; font-weight: bold;}
.java5 .kw72 {color: #003399; font-weight: bold;}
.java5 .kw73 {color: #003399; font-weight: bold;}
.java5 .kw74 {color: #003399; font-weight: bold;}
.java5 .kw75 {color: #003399; font-weight: bold;}
.java5 .kw76 {color: #003399; font-weight: bold;}
.java5 .kw77 {color: #003399; font-weight: bold;}
.java5 .kw78 {color: #003399; font-weight: bold;}
.java5 .kw79 {color: #003399; font-weight: bold;}
.java5 .kw80 {color: #003399; font-weight: bold;}
.java5 .kw81 {color: #003399; font-weight: bold;}
.java5 .kw82 {color: #003399; font-weight: bold;}
.java5 .kw83 {color: #003399; font-weight: bold;}
.java5 .kw84 {color: #003399; font-weight: bold;}
.java5 .kw85 {color: #003399; font-weight: bold;}
.java5 .kw86 {color: #003399; font-weight: bold;}
.java5 .kw87 {color: #003399; font-weight: bold;}
.java5 .kw88 {color: #003399; font-weight: bold;}
.java5 .kw89 {color: #003399; font-weight: bold;}
.java5 .kw90 {color: #003399; font-weight: bold;}
.java5 .kw91 {color: #003399; font-weight: bold;}
.java5 .kw92 {color: #003399; font-weight: bold;}
.java5 .kw93 {color: #003399; font-weight: bold;}
.java5 .kw94 {color: #003399; font-weight: bold;}
.java5 .kw95 {color: #003399; font-weight: bold;}
.java5 .kw96 {color: #003399; font-weight: bold;}
.java5 .kw97 {color: #003399; font-weight: bold;}
.java5 .kw98 {color: #003399; font-weight: bold;}
.java5 .kw99 {color: #003399; font-weight: bold;}
.java5 .kw100 {color: #003399; font-weight: bold;}
.java5 .kw101 {color: #003399; font-weight: bold;}
.java5 .kw102 {color: #003399; font-weight: bold;}
.java5 .kw103 {color: #003399; font-weight: bold;}
.java5 .kw104 {color: #003399; font-weight: bold;}
.java5 .kw105 {color: #003399; font-weight: bold;}
.java5 .kw106 {color: #003399; font-weight: bold;}
.java5 .kw107 {color: #003399; font-weight: bold;}
.java5 .kw108 {color: #003399; font-weight: bold;}
.java5 .kw109 {color: #003399; font-weight: bold;}
.java5 .kw110 {color: #003399; font-weight: bold;}
.java5 .kw111 {color: #003399; font-weight: bold;}
.java5 .kw112 {color: #003399; font-weight: bold;}
.java5 .kw113 {color: #003399; font-weight: bold;}
.java5 .kw114 {color: #003399; font-weight: bold;}
.java5 .kw115 {color: #003399; font-weight: bold;}
.java5 .kw116 {color: #003399; font-weight: bold;}
.java5 .kw117 {color: #003399; font-weight: bold;}
.java5 .kw118 {color: #003399; font-weight: bold;}
.java5 .kw119 {color: #003399; font-weight: bold;}
.java5 .kw120 {color: #003399; font-weight: bold;}
.java5 .kw121 {color: #003399; font-weight: bold;}
.java5 .kw122 {color: #003399; font-weight: bold;}
.java5 .kw123 {color: #003399; font-weight: bold;}
.java5 .kw124 {color: #003399; font-weight: bold;}
.java5 .kw125 {color: #003399; font-weight: bold;}
.java5 .kw126 {color: #003399; font-weight: bold;}
.java5 .kw127 {color: #003399; font-weight: bold;}
.java5 .kw128 {color: #003399; font-weight: bold;}
.java5 .kw129 {color: #003399; font-weight: bold;}
.java5 .kw130 {color: #003399; font-weight: bold;}
.java5 .kw131 {color: #003399; font-weight: bold;}
.java5 .kw132 {color: #003399; font-weight: bold;}
.java5 .kw133 {color: #003399; font-weight: bold;}
.java5 .kw134 {color: #003399; font-weight: bold;}
.java5 .kw135 {color: #003399; font-weight: bold;}
.java5 .kw136 {color: #003399; font-weight: bold;}
.java5 .kw137 {color: #003399; font-weight: bold;}
.java5 .kw138 {color: #003399; font-weight: bold;}
.java5 .kw139 {color: #003399; font-weight: bold;}
.java5 .kw140 {color: #003399; font-weight: bold;}
.java5 .kw141 {color: #003399; font-weight: bold;}
.java5 .kw142 {color: #003399; font-weight: bold;}
.java5 .kw143 {color: #003399; font-weight: bold;}
.java5 .kw144 {color: #003399; font-weight: bold;}
.java5 .kw145 {color: #003399; font-weight: bold;}
.java5 .kw146 {color: #003399; font-weight: bold;}
.java5 .kw147 {color: #003399; font-weight: bold;}
.java5 .kw148 {color: #003399; font-weight: bold;}
.java5 .kw149 {color: #003399; font-weight: bold;}
.java5 .kw150 {color: #003399; font-weight: bold;}
.java5 .kw151 {color: #003399; font-weight: bold;}
.java5 .kw152 {color: #003399; font-weight: bold;}
.java5 .kw153 {color: #003399; font-weight: bold;}
.java5 .kw154 {color: #003399; font-weight: bold;}
.java5 .kw155 {color: #003399; font-weight: bold;}
.java5 .kw156 {color: #003399; font-weight: bold;}
.java5 .kw157 {color: #003399; font-weight: bold;}
.java5 .kw158 {color: #003399; font-weight: bold;}
.java5 .kw159 {color: #003399; font-weight: bold;}
.java5 .kw160 {color: #003399; font-weight: bold;}
.java5 .kw161 {color: #003399; font-weight: bold;}
.java5 .kw162 {color: #003399; font-weight: bold;}
.java5 .kw163 {color: #003399; font-weight: bold;}
.java5 .kw164 {color: #003399; font-weight: bold;}
.java5 .kw165 {color: #003399; font-weight: bold;}
.java5 .kw166 {color: #003399; font-weight: bold;}
.java5 .co1 {color: #666666; font-style: italic;}
.java5 .co2 {color: #006699;}
.java5 .co3 {color: #008000; font-style: italic; font-weight: bold;}
.java5 .coMULTI {color: #666666; font-style: italic;}
.java5 .es0 {color: #000099; font-weight: bold;}
.java5 .br0 {color: #009900;}
.java5 .sy0 {color: #339933;}
.java5 .st0 {color: #0000ff;}
.java5 .nu0 {color: #cc66cc;}
.java5 .me1 {color: #006633;}
.java5 .me2 {color: #006633;}
.java5 span.xtra { display:block; }
--!></style>
<p><body></p>
<p>If you&#8217;ve ever integrated search into your website, chances are you&#8217;ve stumbled across <a href="http://lucene.apache.org/solr/">Solr</a> and its close relative, <a href="http://lucene.apache.org/">Lucene</a>. Solr is a popular, blazing fast open source enterprise search platform from the Apache Lucene project. Its major features include powerful full-text search, hit highlighting, faceted search, dynamic clustering, database integration, rich document (e.g., Word, PDF) handling, and geospatial search.</p>
<p>Solr is highly scalable, providing distributed search and index replication, and it powers the search and navigation features of many of the world&#8217;s largest internet sites, including ZoomInfo. Here at Zoom, we use Solr pervasively &#8211; it&#8217;s integrated as a service layer and powers everything from our website, to our API, to our CRM integrations, to our data services products.</p>
<p>Zoom&#8217;s Solr index is bigger than most &#8211; ours hosts roughly 100 million person and company profiles and serves millions of requests per day. Being such a pivotal part of our infrastructure, you can be darn sure that we thoroughly test our indexing and search service layers.</p>
<p>Simplified a bit, one way that we test Solr is by feeding it documents and asking it queries as part of a ~100k document regression suite. The hardest part was figuring how to set up the testing framework properly to ensure both correctness and isolation. You don&#8217;t want tests stepping on each other&#8217;s toes, now do you? <img src='http://www.zoominfo.com/business/components/com_wordpress/wp/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>It turns out that there is a supported (though woefully under-documented) way to run a Solr Server right in-process. No need for an application container, not even Jetty. This ends up being not only a great building block for a testing framework, but a fantastic way to get around one of Solr&#8217;s biggest limitations &#8211; that it&#8217;s insanely slow if you need to return more than a few pages of results. By stacking things the way we did, you can get all of the benefits of both Solr and Lucene, with none of the drawbacks. More on that later.</p>
<p>Now, I&#8217;ll preface this by warning you that this approach won&#8217;t do for testing Solr&#8217;s performance, sharding, or replication features. But in our experience, it&#8217;s a darn good way to do functional tests. Let&#8217;s take a look.</p>
<p>We start off with a generic class meant to encapsulate access to our Solr server. This is a dumbed-down version of Zoom&#8217;s InProcessSolrServer class. In our version, we do some additional specialization, like deploying our custom solrconfig.xml, schema, stop words list, plugins, and the like. That would needlessly complicate the example, though. What the class amounts to is a lot of boring boilerplate to create a delegate EmbeddedSolrServer that we&#8217;ll pass each request to. Importantly, in Solr, a &#8220;request&#8221; can be any command &#8211; it could be a query, an instruction to index a document, or anything in between. Tying this back to &#8220;normal&#8221; Solr, the usual HTTP-based servlet embedded in Jetty does something just like this. We add a few small utility methods at the end, because they&#8217;re useful for stacking our embedded Solr instance with Lucene.</p>
<p>So now that we can embed Solr in-process, how should we leverage that in our testing frameworks? Zoom has two general approaches:</p>
<ol>
<li>For tests that explicitly involve our &#8220;indexing&#8221; service, create an empty InProcessSolrServer and feed it documents. To test that indexing worked as-expected, we either:
<ol>
<li>Run a comprehensive set of queries against the Solr Server, save the results to XML, and &#8220;diff&#8221; the results against some baseline.
<li>Use the Lucene integration to dump the index&#8217;s stored fields to some more human-readable form, like XML or CSV, and then &#8220;diff&#8221; the results against some baseline.
</ol>
<li>For tests that are more consumers of the index, we pre-can indexes inside of ZIP archives. Our test&#8217;s setup method extracts the index, wraps it in an InProcessSolrServer, and then runs a set of queries against that.
</ol>
<p>The second code snippet below roughly illustrates how we do option #2.
</p>
<p>Finally, let&#8217;s look at how to get the best of both the Solr and Lucene worlds. The final code snippet is a simple method that lets you execute Solr queries and get back a Lucene DocIterator object. This lets you use your Solr plugins, sorting algorithms, query syntax, sort order, and &#8211; most importantly &#8211; your Solr-based <strong>code</strong>, while being able to efficiently enumerate <strong>all</strong> of the documents in your result set. For instance, a &#8220;*:*&#8221; query at Zoom will match 100 million documents, and this approach can export them all to a massive CSV file in roughly an hour. For each matching Lucene document, a simple callback is invoked. Some utility code for converting between Solr and Lucene documents is also included, so that your existing Solr-based code can continue to work without modification.</p>
<hr />
<div class="java5">
<span class="co3">/**<br />
&nbsp;* This code is provided under the MIT License (http://www.opensource.org/licenses/mit-license.php).<br />
&nbsp;* It depends on the following 3rd-party packages:<br />
&nbsp;* <br />
&nbsp;* * Apache Solr: http://lucene.apache.org/solr/<br />
&nbsp;* * Spring Framework: http://www.springsource.org/<br />
&nbsp;*/</span><br />
<span class="kw2">package</span> <span class="co2">com.zoominfo.util.solrembed</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">java.io.Closeable</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.File</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.IOException</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">javax.xml.parsers.ParserConfigurationException</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">org.apache.solr.client.solrj.SolrServer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.client.solrj.SolrRequest</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.client.solrj.SolrServerException</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.common.util.NamedList</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.core.CoreDescriptor</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.core.CoreContainer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.client.solrj.embedded.EmbeddedSolrServer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.core.SolrCore</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.schema.IndexSchema</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.search.SolrIndexSearcher</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.solr.util.RefCounted</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.springframework.beans.factory.annotation.Required</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.xml.sax.SAXException</span><span class="sy0">;</span></p>
<p><span class="co3">/**<br />
&nbsp;* A class that manages the life-cycle of an in-process Solr server.<br />
&nbsp;*/</span><br />
<span class="kw2">public</span> <span class="kw2">class</span> InProcessSolrServer <span class="kw2">extends</span> SolrServer <span class="kw2">implements</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/Closeable.html"><span class="kw20">Closeable</span></a> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">private</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> solrdir = <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> datadir = <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> SolrServer delegate = <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <span class="kw2">transient</span> SolrCore core = <span class="kw4">null</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;Sets your Solr root directory. In Solr&#8217;s documentation,<br />
&nbsp; &nbsp; &nbsp;* this is generally referred to as &quot;/solr-root&quot;. Your &quot;conf&quot;<br />
&nbsp; &nbsp; &nbsp;* directory (containing your schema, stopwords, synonyms, &#8230;)<br />
&nbsp; &nbsp; &nbsp;* will be a subdirectory of this.&lt;/p&gt;.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param solrdir<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; @Required<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">final</span> <span class="kw3">void</span> setSolrdir<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> solrdir<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">this</span>.<span class="me1">solrdir</span> = solrdir<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/System.html"><span class="kw21">System</span></a>.<span class="me1">setProperty</span><span class="br0">&#40;</span><span class="st0">&quot;solr.home&quot;</span>, solrdir.<span class="me1">getPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw2">this</span>.<span class="me1">datadir</span> == <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setDatadir<span class="br0">&#40;</span><span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a><span class="br0">&#40;</span>solrdir, <span class="st0">&quot;data&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;Sets your Solr data directory. This is the parent directory<br />
&nbsp; &nbsp; &nbsp;* of your &quot;index&quot; and &quot;spellchecker&quot; directories.&lt;/p&gt;<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @param datadir<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">final</span> <span class="kw3">void</span> setDatadir<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> datadir<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">this</span>.<span class="me1">datadir</span> = datadir<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/System.html"><span class="kw21">System</span></a>.<span class="me1">setProperty</span><span class="br0">&#40;</span><span class="st0">&quot;solr.data.dir&quot;</span>, datadir.<span class="me1">getPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;The only @SolrServer method that you need to override. This method<br />
&nbsp; &nbsp; &nbsp;* passes all queries and indexing events on to an in-process delegate.&lt;/p&gt;<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @param req<br />
&nbsp; &nbsp; &nbsp;* @return<br />
&nbsp; &nbsp; &nbsp;* @throws SolrServerException<br />
&nbsp; &nbsp; &nbsp;* @throws IOException<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a><br />
&nbsp; &nbsp; <span class="kw2">public</span> NamedList<span class="sy0">&lt;</span><a href="http://www.google.com/search?sitesearch=java.sun.com&amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+Object"><span class="kw166">Object</span></a><span class="sy0">&gt;</span> request<span class="br0">&#40;</span><span class="kw2">final</span> SolrRequest req<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throws</span> SolrServerException,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> getDelegate<span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">request</span><span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw2">final</span> SolrServerException e<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> e<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> e<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> e<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Exception.html"><span class="kw21">Exception</span></a> e<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> SolrServerException<span class="br0">&#40;</span>e<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">synchronized</span> <span class="kw3">void</span> close<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>core <span class="sy0">!</span>= <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; core.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; core = <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a><br />
&nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/SuppressWarnings.html"><span class="kw21">SuppressWarnings</span></a><span class="br0">&#40;</span><span class="st0">&quot;FinalizeDeclaration&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> finalize<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Throwable.html"><span class="kw21">Throwable</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; close<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">super</span>.<span class="me1">finalize</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* This method creates an in-process Solr server that otherwise behaves just<br />
&nbsp; &nbsp; &nbsp;* as you&#8217;d expect.<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <span class="kw2">synchronized</span> SolrServer getDelegate<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> SolrServerException <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>delegate <span class="sy0">!</span>= <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> delegate<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> solrconfigXml = <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a><span class="br0">&#40;</span><span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a><span class="br0">&#40;</span>solrdir, <span class="st0">&quot;conf&quot;</span><span class="br0">&#41;</span>, <span class="st0">&quot;solrconfig.xml&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CoreContainer container = <span class="kw2">new</span> CoreContainer<span class="br0">&#40;</span>solrdir.<span class="me1">getPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, solrconfigXml<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CoreDescriptor descriptor = <span class="kw2">new</span> CoreDescriptor<span class="br0">&#40;</span>container, <span class="st0">&quot;core1&quot;</span>, solrdir.<span class="me1">getCanonicalPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; core = container.<span class="me1">create</span><span class="br0">&#40;</span>descriptor<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; container.<span class="me1">register</span><span class="br0">&#40;</span><span class="st0">&quot;core1&quot;</span>, core, <span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delegate = <span class="kw2">new</span> EmbeddedSolrServer<span class="br0">&#40;</span>container, <span class="st0">&quot;core1&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> delegate<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/xml/parsers/ParserConfigurationException.html"><span class="kw127">ParserConfigurationException</span></a> ex<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> SolrServerException<span class="br0">&#40;</span>ex<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/org/xml/sax/SAXException.html"><span class="kw163">SAXException</span></a> ex<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> SolrServerException<span class="br0">&#40;</span>ex<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">catch</span> <span class="br0">&#40;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> ex<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> SolrServerException<span class="br0">&#40;</span>ex<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* SolrIndexSearcher adds schema awareness and caching functionality over the Lucene IndexSearcher.<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @return<br />
&nbsp; &nbsp; &nbsp;* @throws SolrServerException<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> RefCounted<span class="sy0">&lt;</span>SolrIndexSearcher<span class="sy0">&gt;</span> getIndexSearcher<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> SolrServerException <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// http://lucene.apache.org/solr/api/org/apache/solr/search/SolrIndexSearcher.html</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; getDelegate<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// force the delegate to be created</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> core.<span class="me1">getSearcher</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* Returns the index schema used by this Solr server<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @return<br />
&nbsp; &nbsp; &nbsp;* @throws SolrServerException<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> IndexSchema getIndexSchema<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> SolrServerException <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; getDelegate<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// force the delegate to be created</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> core.<span class="me1">getSchema</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<hr />
<div class="java5"><span class="kw2">package</span> <span class="co2">com.zoominfo.util.solrembed</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">org.apache.solr.client.solrj.SolrServer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.IOException</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">com.zoominfo.util.ZipUtil</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">com.zoominfo.util.solrembed.InProcessSolrServer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.File</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="kw2">static</span> <span class="co2">org.apache.commons.io.FileUtils.deleteDirectory</span><span class="sy0">;</span></p>
<p><span class="kw2">public</span> <span class="kw2">abstract</span> <span class="kw2">class</span> InProcessSolrServerTestBase <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">private</span> InProcessSolrServer solrServer = <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> solrOutFolder = <span class="kw4">null</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">public</span> SolrServer getSolrServer<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> solrServer<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;Deploys a pre-built Solr index, and creates an in-process Solr server.<br />
&nbsp; &nbsp; &nbsp;* This is meant to be called from an @Before or @BeforeClass type of method.&lt;/p&gt;<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @param solrIndexZip a pre-built Solr index, bundled into a ZIP<br />
&nbsp; &nbsp; &nbsp;* @throws IOException<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> deploySolrIndex<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> solrIndexZip<span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">assert</span> solrOutFolder == <span class="kw4">null</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; solrOutFolder = <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a>.<span class="me1">createTempFile</span><span class="br0">&#40;</span><span class="st0">&quot;solr&quot;</span>, <span class="st0">&quot;index&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; solrOutFolder.<span class="me1">delete</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; solrOutFolder.<span class="me1">mkdirs</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// unzip a canned solr index. code not provided.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ZipUtil.<span class="me1">unzipFolder</span><span class="br0">&#40;</span>solrIndexZip, solrOutFolder<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// create an in-process solr server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; solrServer = <span class="kw2">new</span> InProcessSolrServer<span class="br0">&#40;</span>solrOutFolder<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;Un-deploys the in-process Solr server.<br />
&nbsp; &nbsp; &nbsp;* Meant to be called from an @After or @AfterClass method.&lt;/p&gt;</p>
<p>&nbsp; &nbsp; &nbsp;* @throws IOException<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> tearDown<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>solrOutFolder <span class="sy0">!</span>= <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; solrServer.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// turn off the solr server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; deleteDirectory<span class="br0">&#40;</span>solrOutFolder<span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// delete the solr directory, recursively</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<hr />
<div class="java5">&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* Runs the specified query, passing every result to the specified Callback argument<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @see SolrIndexSearcher.getDocList<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param solrServer the Solr Server you want to search<br />
&nbsp; &nbsp; &nbsp;* @param query the Solr query<br />
&nbsp; &nbsp; &nbsp;* @param filterList the list of documents to not return. may be null<br />
&nbsp; &nbsp; &nbsp;* @param sort criteria by which to sort (if null, query relevance is used)<br />
&nbsp; &nbsp; &nbsp;* @param start offset into the list of documents to return<br />
&nbsp; &nbsp; &nbsp;* @param length maximum number of documents to return. -1 returns all documents<br />
&nbsp; &nbsp; &nbsp;* @param callback action performed for each matching document<br />
&nbsp; &nbsp; &nbsp;* @param closeIndexSearcher pass true to keep the searcher open for more queries<br />
&nbsp; &nbsp; &nbsp;* @throws Exception<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">static</span> <span class="kw3">void</span> run<span class="br0">&#40;</span><span class="kw2">final</span> InProcessSolrServer solrServer, <span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/management/Query.html"><span class="kw67">Query</span></a> query,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">final</span> <a href="http://www.google.com/search?sitesearch=java.sun.com&amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+List"><span class="kw166">List</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/management/Query.html"><span class="kw67">Query</span></a><span class="sy0">&gt;</span> filterList, <span class="kw2">final</span> Sort sort,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">final</span> <span class="kw3">int</span> start, <span class="kw3">int</span> length, <span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/security/auth/callback/Callback.html"><span class="kw91">Callback</span></a> callback, <span class="kw2">final</span> <span class="kw3">boolean</span> closeIndexSearcher<span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Exception.html"><span class="kw21">Exception</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; RefCounted<span class="sy0">&lt;</span>SolrIndexSearcher<span class="sy0">&gt;</span> indexSearcherRef = <span class="kw4">null</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexSearcherRef = solrServer.<span class="me1">getIndexSearcher</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SolrIndexSearcher indexSearcher = indexSearcherRef.<span class="me1">get</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>length <span class="sy0">&lt;</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; length = indexSearcher.<span class="me1">getIndexReader</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">maxDoc</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DocList docList = indexSearcher.<span class="me1">getDocList</span><span class="br0">&#40;</span>query, filterList, sort, start, length, <span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback.<span class="me1">setIndexSchema</span><span class="br0">&#40;</span>solrServer.<span class="me1">getIndexSchema</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DocIterator iter = docList.<span class="me1">iterator</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>iter.<span class="me1">hasNext</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?sitesearch=java.sun.com&amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+Document"><span class="kw166">Document</span></a> doc = indexSearcher.<span class="me1">doc</span><span class="br0">&#40;</span>iter.<span class="me1">nextDoc</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback.<span class="me1">collect</span><span class="br0">&#40;</span>doc<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>closeIndexSearcher<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexSearcher.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw2">finally</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>indexSearcherRef <span class="sy0">!</span>= <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexSearcherRef.<span class="me1">decref</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* A utility method that converts a Lucene document to a Solr document<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @param doc a Lucene document<br />
&nbsp; &nbsp; &nbsp;* @return an equivalent Solr document<br />
&nbsp; &nbsp; &nbsp;* @throws Exception<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> SolrDocument convertToSolrDocument<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://www.google.com/search?sitesearch=java.sun.com&amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+Document"><span class="kw166">Document</span></a> doc<span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Exception.html"><span class="kw21">Exception</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; SolrDocument solrDoc = <span class="kw2">new</span> SolrDocument<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// load the solr doc from the lucene doc</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">new</span> org.<span class="me1">apache</span>.<span class="me1">solr</span>.<span class="me1">update</span>.<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/xml/parsers/DocumentBuilder.html"><span class="kw127">DocumentBuilder</span></a><span class="br0">&#40;</span>schema<span class="br0">&#41;</span>.<span class="me1">loadStoredFields</span><span class="br0">&#40;</span>solrDoc, doc<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> solrDoc<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* A utility method that converts a Solr document to a Lucene document<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param doc a Solr document<br />
&nbsp; &nbsp; &nbsp;* @return an equivalent Lucene document<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <a href="http://www.google.com/search?sitesearch=java.sun.com&amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+Document"><span class="kw166">Document</span></a> convertToLuceneDocument<span class="br0">&#40;</span><span class="kw2">final</span> SolrDocument doc<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// load the lucene doc from the solr doc</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/javax/xml/parsers/DocumentBuilder.html"><span class="kw127">DocumentBuilder</span></a>.<span class="me1">toDocument</span><span class="br0">&#40;</span>org.<span class="me1">apache</span>.<span class="me1">solr</span>.<span class="me1">client</span>.<span class="me1">solrj</span>.<span class="me1">util</span>.<span class="me1">ClientUtils</span>.<span class="me1">toSolrInputDocument</span><span class="br0">&#40;</span>doc<span class="br0">&#41;</span>, schema<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></div>
<p></body><br />
</html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2012/04/automating-solr-tests-using-embeddedsolrserver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automating FTP Tests using Apache Mina</title>
		<link>http://www.zoominfo.com/business/blog/2012/04/automating-ftp-tests-using-apache-mina/</link>
		<comments>http://www.zoominfo.com/business/blog/2012/04/automating-ftp-tests-using-apache-mina/#comments</comments>
		<pubDate>Tue, 03 Apr 2012 14:52:57 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6331</guid>
		<description />
			<content:encoded><![CDATA[<p><head></p>
<style type="text/css"><!--
/**
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 */
.java5  {font-family:monospace;color: #006; border: 1px solid #d0d0d0; background-color: #f0f0f0;}
.java5 a:link {color: #000060;}
.java5 a:hover {background-color: #f0f000;}
.java5 .imp {font-weight: bold; color: red;}
.java5 .kw1 {color: #000000;  font-weight: bold;}
.java5 .kw2 {color: #000000; font-weight: bold;}
.java5 .kw3 {color: #006600; font-weight: bold;}
.java5 .kw4 {color: #006600; font-weight: bold;}
.java5 .kw5 {color: #003399; font-weight: bold;}
.java5 .kw6 {color: #003399; font-weight: bold;}
.java5 .kw7 {color: #003399; font-weight: bold;}
.java5 .kw8 {color: #003399; font-weight: bold;}
.java5 .kw9 {color: #003399; font-weight: bold;}
.java5 .kw10 {color: #003399; font-weight: bold;}
.java5 .kw11 {color: #003399; font-weight: bold;}
.java5 .kw12 {color: #003399; font-weight: bold;}
.java5 .kw13 {color: #003399; font-weight: bold;}
.java5 .kw14 {color: #003399; font-weight: bold;}
.java5 .kw15 {color: #003399; font-weight: bold;}
.java5 .kw16 {color: #003399; font-weight: bold;}
.java5 .kw17 {color: #003399; font-weight: bold;}
.java5 .kw18 {color: #003399; font-weight: bold;}
.java5 .kw19 {color: #003399; font-weight: bold;}
.java5 .kw20 {color: #003399; font-weight: bold;}
.java5 .kw21 {color: #003399; font-weight: bold;}
.java5 .kw22 {color: #003399; font-weight: bold;}
.java5 .kw23 {color: #003399; font-weight: bold;}
.java5 .kw24 {color: #003399; font-weight: bold;}
.java5 .kw25 {color: #003399; font-weight: bold;}
.java5 .kw26 {color: #003399; font-weight: bold;}
.java5 .kw27 {color: #003399; font-weight: bold;}
.java5 .kw28 {color: #003399; font-weight: bold;}
.java5 .kw29 {color: #003399; font-weight: bold;}
.java5 .kw30 {color: #003399; font-weight: bold;}
.java5 .kw31 {color: #003399; font-weight: bold;}
.java5 .kw32 {color: #003399; font-weight: bold;}
.java5 .kw33 {color: #003399; font-weight: bold;}
.java5 .kw34 {color: #003399; font-weight: bold;}
.java5 .kw35 {color: #003399; font-weight: bold;}
.java5 .kw36 {color: #003399; font-weight: bold;}
.java5 .kw37 {color: #003399; font-weight: bold;}
.java5 .kw38 {color: #003399; font-weight: bold;}
.java5 .kw39 {color: #003399; font-weight: bold;}
.java5 .kw40 {color: #003399; font-weight: bold;}
.java5 .kw41 {color: #003399; font-weight: bold;}
.java5 .kw42 {color: #003399; font-weight: bold;}
.java5 .kw43 {color: #003399; font-weight: bold;}
.java5 .kw44 {color: #003399; font-weight: bold;}
.java5 .kw45 {color: #003399; font-weight: bold;}
.java5 .kw46 {color: #003399; font-weight: bold;}
.java5 .kw47 {color: #003399; font-weight: bold;}
.java5 .kw48 {color: #003399; font-weight: bold;}
.java5 .kw49 {color: #003399; font-weight: bold;}
.java5 .kw50 {color: #003399; font-weight: bold;}
.java5 .kw51 {color: #003399; font-weight: bold;}
.java5 .kw52 {color: #003399; font-weight: bold;}
.java5 .kw53 {color: #003399; font-weight: bold;}
.java5 .kw54 {color: #003399; font-weight: bold;}
.java5 .kw55 {color: #003399; font-weight: bold;}
.java5 .kw56 {color: #003399; font-weight: bold;}
.java5 .kw57 {color: #003399; font-weight: bold;}
.java5 .kw58 {color: #003399; font-weight: bold;}
.java5 .kw59 {color: #003399; font-weight: bold;}
.java5 .kw60 {color: #003399; font-weight: bold;}
.java5 .kw61 {color: #003399; font-weight: bold;}
.java5 .kw62 {color: #003399; font-weight: bold;}
.java5 .kw63 {color: #003399; font-weight: bold;}
.java5 .kw64 {color: #003399; font-weight: bold;}
.java5 .kw65 {color: #003399; font-weight: bold;}
.java5 .kw66 {color: #003399; font-weight: bold;}
.java5 .kw67 {color: #003399; font-weight: bold;}
.java5 .kw68 {color: #003399; font-weight: bold;}
.java5 .kw69 {color: #003399; font-weight: bold;}
.java5 .kw70 {color: #003399; font-weight: bold;}
.java5 .kw71 {color: #003399; font-weight: bold;}
.java5 .kw72 {color: #003399; font-weight: bold;}
.java5 .kw73 {color: #003399; font-weight: bold;}
.java5 .kw74 {color: #003399; font-weight: bold;}
.java5 .kw75 {color: #003399; font-weight: bold;}
.java5 .kw76 {color: #003399; font-weight: bold;}
.java5 .kw77 {color: #003399; font-weight: bold;}
.java5 .kw78 {color: #003399; font-weight: bold;}
.java5 .kw79 {color: #003399; font-weight: bold;}
.java5 .kw80 {color: #003399; font-weight: bold;}
.java5 .kw81 {color: #003399; font-weight: bold;}
.java5 .kw82 {color: #003399; font-weight: bold;}
.java5 .kw83 {color: #003399; font-weight: bold;}
.java5 .kw84 {color: #003399; font-weight: bold;}
.java5 .kw85 {color: #003399; font-weight: bold;}
.java5 .kw86 {color: #003399; font-weight: bold;}
.java5 .kw87 {color: #003399; font-weight: bold;}
.java5 .kw88 {color: #003399; font-weight: bold;}
.java5 .kw89 {color: #003399; font-weight: bold;}
.java5 .kw90 {color: #003399; font-weight: bold;}
.java5 .kw91 {color: #003399; font-weight: bold;}
.java5 .kw92 {color: #003399; font-weight: bold;}
.java5 .kw93 {color: #003399; font-weight: bold;}
.java5 .kw94 {color: #003399; font-weight: bold;}
.java5 .kw95 {color: #003399; font-weight: bold;}
.java5 .kw96 {color: #003399; font-weight: bold;}
.java5 .kw97 {color: #003399; font-weight: bold;}
.java5 .kw98 {color: #003399; font-weight: bold;}
.java5 .kw99 {color: #003399; font-weight: bold;}
.java5 .kw100 {color: #003399; font-weight: bold;}
.java5 .kw101 {color: #003399; font-weight: bold;}
.java5 .kw102 {color: #003399; font-weight: bold;}
.java5 .kw103 {color: #003399; font-weight: bold;}
.java5 .kw104 {color: #003399; font-weight: bold;}
.java5 .kw105 {color: #003399; font-weight: bold;}
.java5 .kw106 {color: #003399; font-weight: bold;}
.java5 .kw107 {color: #003399; font-weight: bold;}
.java5 .kw108 {color: #003399; font-weight: bold;}
.java5 .kw109 {color: #003399; font-weight: bold;}
.java5 .kw110 {color: #003399; font-weight: bold;}
.java5 .kw111 {color: #003399; font-weight: bold;}
.java5 .kw112 {color: #003399; font-weight: bold;}
.java5 .kw113 {color: #003399; font-weight: bold;}
.java5 .kw114 {color: #003399; font-weight: bold;}
.java5 .kw115 {color: #003399; font-weight: bold;}
.java5 .kw116 {color: #003399; font-weight: bold;}
.java5 .kw117 {color: #003399; font-weight: bold;}
.java5 .kw118 {color: #003399; font-weight: bold;}
.java5 .kw119 {color: #003399; font-weight: bold;}
.java5 .kw120 {color: #003399; font-weight: bold;}
.java5 .kw121 {color: #003399; font-weight: bold;}
.java5 .kw122 {color: #003399; font-weight: bold;}
.java5 .kw123 {color: #003399; font-weight: bold;}
.java5 .kw124 {color: #003399; font-weight: bold;}
.java5 .kw125 {color: #003399; font-weight: bold;}
.java5 .kw126 {color: #003399; font-weight: bold;}
.java5 .kw127 {color: #003399; font-weight: bold;}
.java5 .kw128 {color: #003399; font-weight: bold;}
.java5 .kw129 {color: #003399; font-weight: bold;}
.java5 .kw130 {color: #003399; font-weight: bold;}
.java5 .kw131 {color: #003399; font-weight: bold;}
.java5 .kw132 {color: #003399; font-weight: bold;}
.java5 .kw133 {color: #003399; font-weight: bold;}
.java5 .kw134 {color: #003399; font-weight: bold;}
.java5 .kw135 {color: #003399; font-weight: bold;}
.java5 .kw136 {color: #003399; font-weight: bold;}
.java5 .kw137 {color: #003399; font-weight: bold;}
.java5 .kw138 {color: #003399; font-weight: bold;}
.java5 .kw139 {color: #003399; font-weight: bold;}
.java5 .kw140 {color: #003399; font-weight: bold;}
.java5 .kw141 {color: #003399; font-weight: bold;}
.java5 .kw142 {color: #003399; font-weight: bold;}
.java5 .kw143 {color: #003399; font-weight: bold;}
.java5 .kw144 {color: #003399; font-weight: bold;}
.java5 .kw145 {color: #003399; font-weight: bold;}
.java5 .kw146 {color: #003399; font-weight: bold;}
.java5 .kw147 {color: #003399; font-weight: bold;}
.java5 .kw148 {color: #003399; font-weight: bold;}
.java5 .kw149 {color: #003399; font-weight: bold;}
.java5 .kw150 {color: #003399; font-weight: bold;}
.java5 .kw151 {color: #003399; font-weight: bold;}
.java5 .kw152 {color: #003399; font-weight: bold;}
.java5 .kw153 {color: #003399; font-weight: bold;}
.java5 .kw154 {color: #003399; font-weight: bold;}
.java5 .kw155 {color: #003399; font-weight: bold;}
.java5 .kw156 {color: #003399; font-weight: bold;}
.java5 .kw157 {color: #003399; font-weight: bold;}
.java5 .kw158 {color: #003399; font-weight: bold;}
.java5 .kw159 {color: #003399; font-weight: bold;}
.java5 .kw160 {color: #003399; font-weight: bold;}
.java5 .kw161 {color: #003399; font-weight: bold;}
.java5 .kw162 {color: #003399; font-weight: bold;}
.java5 .kw163 {color: #003399; font-weight: bold;}
.java5 .kw164 {color: #003399; font-weight: bold;}
.java5 .kw165 {color: #003399; font-weight: bold;}
.java5 .kw166 {color: #003399; font-weight: bold;}
.java5 .co1 {color: #666666; font-style: italic;}
.java5 .co2 {color: #006699;}
.java5 .co3 {color: #008000; font-style: italic; font-weight: bold;}
.java5 .coMULTI {color: #666666; font-style: italic;}
.java5 .es0 {color: #000099; font-weight: bold;}
.java5 .br0 {color: #009900;}
.java5 .sy0 {color: #339933;}
.java5 .st0 {color: #0000ff;}
.java5 .nu0 {color: #cc66cc;}
.java5 .me1 {color: #006633;}
.java5 .me2 {color: #006633;}
.java5 span.xtra { display:block; }
--!></style>
<p></head></p>
<p><body></p>
<p>Few things are worse than tracking down a Heisenbug in your testing framework. As a responsible developer, you hate breaking the build. Before checking in your code, you made sure that all of the tests pass locally. But you just got that dreaded email &#8211; the build is broken. Worse still, it turns out that only every n<sup>th</sup> build fails. Most of the builds still pass. You scratch your head. What&#8217;s going on?</p>
<p>In my experience, these Heisenbugs are usually caused by tests that depend on external resources like a database, NoSQL server, filesystem, or Solr. Sometimes, they&#8217;re caused by a system outage like a network failure. More often, the root cause is a race condition triggered by two tests updating the same shared resource. Regardless of the cause, what it is above all else is <em>frustrating</em>.</p>
<p>Oftentimes, this happens when you&#8217;re automating some larger functional test or integration test. Many organizations that encounter this sort of problem usually adopt a &#8220;tiered&#8221; approach, resembling something like this:</p>
<ul>
<li>Mock out external dependencies, and keep your unit tests simple. These tests can&#8217;t reference any external resources, and are run constantly (more-or-less) by your CI system.
<li>Run bigger functional &#038; system tests asynchronously &#8211; usually nightly or weekly. These tests can depend on external resources and generally take longer to run than unit tests.
</ul>
<p>I&#8217;ve always been a little leery of this sort of model. Organizations usually don&#8217;t strictly adhere to this separation. Testing budgets are always tight, and corners often get cut. But even if you&#8217;ve implemented this model perfectly, what you&#8217;ve done is introduced friction into your development process. You&#8217;ve increased the time it takes between writing a line of code and knowing its impact on your production environment. You&#8217;ve reduced the universe of meaningful tests that your developers can run on their own. Usually, this is better than what you had before &#8211; i.e. before you had functional &#038; system tests. But you can do better still.</p>
<p>One partial (and popular) solution to this problem are mock objects. Mock objects are great at testing your &#8220;meat and potatoes&#8221; main code path and really excel at helping you write effective unit tests. But in my experience they really fall short on data-driven or system tests. Ideally, you&#8217;d like for each of your developers to have a smaller, isolated copy of your production environment to test their changes in, with lots &#038; lots of data to test against.</p>
<p>What if I told you that you could have a miniature copy of your production environment &#8211; your database, FTP server, Solr server, and Cassandra NoSQL database running right in-process as part of your testing framework? That you could have meaningful data-driven tests with <strong>no</strong> external dependencies. That you could have meaningful data-driven tests that you could run from an airplane. Today&#8217;s Open Source ecosystem makes this easy. Over the next few posts, I&#8217;ll show you how.</p>
<hr />
<p>An important part of Zoom&#8217;s workflow involves interchanging data over FTP. In today&#8217;s world of RESTful APIs, this process sounds a little dated to be sure. But whether it be for exchanging data with customers or with vendors, FTP is a neat little protocol that doesn&#8217;t want to go away.</p>
<p>To ensure that our code that interacts with these FTP servers doesn&#8217;t break, we&#8217;ve implemented a testing framework that embeds <a href="http://mina.apache.org/ftpserver/">Apache Mina&#8217;s FtpServer</a> in-process. With some small changes, you should be able to inherit this class for your own needs and just fill in the business logic.</p>
<p>The class starts by creating a sandboxed FTP server in its @Before method. The FTP server is configured with a single dummy user, running on any available port, and pointed at some empty temporary directory on your local filesystem. Since we used @Before and not @BeforeClass, a new sandboxed FTP server will be created for every @Test. In our setup method, an FtpClient object is created, connected to this in-process server, and ready to use in your @Tests. After each @Test is completed, the FtpClient is disconnected, the server is shut down, and the directory is deleted from your filesystem, including any files that you might have put there as part of your business logic. Now, you have one fewer thing to configure on your staging environment or development VM. Let&#8217;s take a look:</p>
<hr />
<div class="java5"><span class="co3">/**<br />
&nbsp;* This code is provided under the MIT License (http://www.opensource.org/licenses/mit-license.php).<br />
&nbsp;* It depends on the following 3rd-party packages:<br />
&nbsp;* <br />
&nbsp;* * Apache Mina FtpServer: http://mina.apache.org/ftpserver/<br />
&nbsp;* * Apache Commons I/O: http://commons.apache.org/io/<br />
&nbsp;* * Apache Commons Net: http://commons.apache.org/net/<br />
&nbsp;* * JUnit: http://www.junit.org/<br />
&nbsp;*/</span><br />
<span class="kw2">package</span> <span class="co2">ftpserverapplication</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">java.io.ByteArrayInputStream</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.File</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.FileOutputStream</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.io.IOException</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">java.util.Properties</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="kw2">static</span> <span class="co2">org.apache.commons.io.FileUtils.deleteDirectory</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">org.apache.ftpserver.FtpServer</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.ftpserver.FtpServerFactory</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.ftpserver.ftplet.FtpException</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.ftpserver.listener.ListenerFactory</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.ftpserver.usermanager.PropertiesUserManagerFactory</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">org.apache.commons.net.ftp.FTP</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.commons.net.ftp.FTPClient</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.apache.commons.net.ftp.FTPReply</span><span class="sy0">;</span></p>
<p><span class="kw2">import</span> <span class="co2">org.junit.After</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.junit.Before</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="co2">org.junit.Test</span><span class="sy0">;</span><br />
<span class="kw2">import</span> <span class="kw2">static</span> <span class="co2">org.junit.Assert.*</span><span class="sy0">;</span></p>
<p><span class="co3">/**<br />
&nbsp;* &lt;p&gt;This class is intended to be a base class for any test that needs to interact<br />
&nbsp;* with a FTP server. It creates a new sandboxed FTP server for each @Test<br />
&nbsp;* that gets executed.&lt;/p&gt;<br />
&nbsp;*/</span><br />
<span class="kw2">public</span> <span class="kw2">class</span> FtpServerTest <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; <span class="co1">// HACK UTILITY METHOD</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> createTempFileName<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/String.html"><span class="kw21">String</span></a> name<span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// File.createTempFile() actually creates the file. We only want a name.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Don&#8217;t use this in production code, as it could be exploited or suffer</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// from race conditions, similar to C&#8217;s &quot;tmpnam()&quot; function.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> f = <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a>.<span class="me1">createTempFile</span><span class="br0">&#40;</span>name, <span class="st0">&quot;.temp&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; f.<span class="me1">delete</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> f<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> FtpServer server<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> propsFile<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> ftpBaseDirectory<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> FTPClient client<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* &lt;p&gt;This method sets up some basic configuration parameters for the FTP Server.<br />
&nbsp; &nbsp; &nbsp;* It creates a single user account, tied to a base directory.&lt;/p&gt;<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param ftpDirectory the root directory for the FTP Server<br />
&nbsp; &nbsp; &nbsp;* @return the FTP Properties file that will drive its configuration<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">private</span> <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> generateFtpProperties<span class="br0">&#40;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> ftpDirectory<span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/util/Properties.html"><span class="kw46">Properties</span></a> props = <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/util/Properties.html"><span class="kw46">Properties</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// create an account for the user &quot;ftpuser&quot; whose password is &quot;password&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// most of these are just &quot;stock&quot; values that won&#8217;t affect your functional</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// testing, so don&#8217;t worry too much about them</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.userpassword&quot;</span>, <span class="st0">&quot;password&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.homedirectory&quot;</span>, ftpDirectory.<span class="me1">getCanonicalPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.enableflag&quot;</span>, <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.writepermission&quot;</span>, <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.maxloginnumber&quot;</span>, <span class="st0">&quot;0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.maxloginperip&quot;</span>, <span class="st0">&quot;0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.idletime&quot;</span>, <span class="st0">&quot;0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.uploadrate&quot;</span>, <span class="st0">&quot;0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver.user.ftpuser.downloadrate&quot;</span>, <span class="st0">&quot;0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// create a sandboxed properties file</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> propsFile = <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a>.<span class="me1">createTempFile</span><span class="br0">&#40;</span><span class="st0">&quot;ftpserver&quot;</span>, <span class="st0">&quot;properties&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/FileOutputStream.html"><span class="kw20">FileOutputStream</span></a> os = <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/FileOutputStream.html"><span class="kw20">FileOutputStream</span></a><span class="br0">&#40;</span>propsFile<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; props.<span class="me1">store</span><span class="br0">&#40;</span>os, <span class="st0">&quot;Apache Mina FtpServer configuration&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; os.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// ensure that the properties file gets cleaned up when the tests are done</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; propsFile.<span class="me1">deleteOnExit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> propsFile<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* Here, we create our in-process FTP Server, as well as a client connected to it.<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; @Before<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw3">void</span> setup<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a>, FtpException <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; FtpServerFactory serverFactory = <span class="kw2">new</span> FtpServerFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// generate a random, sandboxed directory that will serve as the base</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// directory for our FTP Server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ftpBaseDirectory = createTempFileName<span class="br0">&#40;</span><span class="st0">&quot;ftpserver&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">boolean</span> createdDirectories = ftpBaseDirectory.<span class="me1">mkdirs</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// create the directory</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>createdDirectories<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a><span class="br0">&#40;</span><span class="st0">&quot;Could not create directory: &quot;</span> + ftpBaseDirectory.<span class="me1">getCanonicalPath</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; propsFile = generateFtpProperties<span class="br0">&#40;</span>ftpBaseDirectory<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; PropertiesUserManagerFactory userManagerFactory = <span class="kw2">new</span> PropertiesUserManagerFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; userManagerFactory.<span class="me1">setPasswordEncryptor</span><span class="br0">&#40;</span><span class="kw2">new</span> ClearTextPasswordEncryptor<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; userManagerFactory.<span class="me1">setFile</span><span class="br0">&#40;</span>propsFile<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; serverFactory.<span class="me1">setUserManager</span><span class="br0">&#40;</span>userManagerFactory.<span class="me1">createUserManager</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; ListenerFactory listenerFactory = <span class="kw2">new</span> ListenerFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// let the ftp server bind to any available port</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; listenerFactory.<span class="me1">setPort</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// replace the default listener</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; serverFactory.<span class="me1">addListener</span><span class="br0">&#40;</span><span class="st0">&quot;default&quot;</span>, listenerFactory.<span class="me1">createListener</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; server = serverFactory.<span class="me1">createServer</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// start the FTP server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; server.<span class="me1">start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// creates a new FTP client</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; client = <span class="kw2">new</span> FTPClient<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// connect to the ftp server on the correct port</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; client.<span class="me1">connect</span><span class="br0">&#40;</span><span class="st0">&quot;127.0.0.1&quot;</span>, serverFactory.<span class="me1">getListener</span><span class="br0">&#40;</span><span class="st0">&quot;default&quot;</span><span class="br0">&#41;</span>.<span class="me1">getPort</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// check the reply code to verify success</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>FTPReply.<span class="me1">isPositiveCompletion</span><span class="br0">&#40;</span>client.<span class="me1">getReplyCode</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.<span class="me1">disconnect</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a><span class="br0">&#40;</span><span class="st0">&quot;FTP server refused connection. Reason: &quot;</span> + client.<span class="me1">getReplyString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// log in to the ftp server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">boolean</span> isLoggedIn = client.<span class="me1">login</span><span class="br0">&#40;</span><span class="st0">&quot;ftpuser&quot;</span>, <span class="st0">&quot;password&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>isLoggedIn<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a><span class="br0">&#40;</span><span class="st0">&quot;Login failed to FTP server. Reason: &quot;</span> + client.<span class="me1">getReplyString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// transfer data in binary mode, otherwise the FTP server will</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// un-helpfully convert line endings for you</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">boolean</span> supportsBinary = client.<span class="me1">setFileType</span><span class="br0">&#40;</span>FTP.<span class="me1">BINARY_FILE_TYPE</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>supportsBinary<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a><span class="br0">&#40;</span><span class="st0">&quot;Could not set mode to &#8216;binary&#8217;. Reason: &quot;</span> + client.<span class="me1">getReplyString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="co3">/**<br />
&nbsp; &nbsp; &nbsp;* This method cleans up the various sandboxes we created and stops the FTP server.<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; @After<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw3">void</span> tearDown<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// disconnect the client</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; client.<span class="me1">disconnect</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// stop the server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; server.<span class="me1">stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// clean up the FTP server&#8217;s properties file</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; propsFile.<span class="me1">delete</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// clean up the temporary ftp directory, recursively</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; deleteDirectory<span class="br0">&#40;</span>ftpBaseDirectory<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; @Test<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw3">void</span> test<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw2">throws</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/String.html"><span class="kw21">String</span></a> remoteFileName = <span class="st0">&quot;test.txt&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">byte</span><span class="br0">&#91;</span><span class="br0">&#93;</span> testTextBytes<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// This block is where you would put your business logic.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// I&#8217;ve dummied up some business logic for illustrative purposes. </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// All this does is create a simple file on the server.</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/String.html"><span class="kw21">String</span></a> testText = <span class="st0">&quot;hello world!<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + <span class="st0">&quot;this file has several lines in it.<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + <span class="st0">&quot;it is an otherwise boring file.&quot;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testTextBytes = testText.<span class="me1">getBytes</span><span class="br0">&#40;</span><span class="st0">&quot;UTF-8&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/ByteArrayInputStream.html"><span class="kw20">ByteArrayInputStream</span></a> localInput = <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/ByteArrayInputStream.html"><span class="kw20">ByteArrayInputStream</span></a><span class="br0">&#40;</span>testTextBytes<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">boolean</span> storedOk = client.<span class="me1">storeFile</span><span class="br0">&#40;</span>remoteFileName, localInput<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localInput.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>storedOk<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">throw</span> <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/IOException.html"><span class="kw20">IOException</span></a><span class="br0">&#40;</span><span class="st0">&quot;Transfer failed to FTP server. Reason: &quot;</span> + client.<span class="me1">getReplyString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// In this block, we assert that our business logic worked appropriately.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// For this use case, we simply assert that the file exists on the local</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// hard drive, and that it has the same size as we&#8217;d expect it to.</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// assert that the file exists</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a> storedFile = <span class="kw2">new</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/io/File.html"><span class="kw20">File</span></a><span class="br0">&#40;</span>ftpBaseDirectory, remoteFileName<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; assertTrue<span class="br0">&#40;</span>storedFile.<span class="me1">exists</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// assert that the file has the correct size in bytes</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">long</span> length = storedFile.<span class="me1">length</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; assertEquals<span class="br0">&#40;</span>testTextBytes.<span class="me1">length</span>, length<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p align="right">-Dominic Lachowicz, <i>Director of Core Development</i></p>
<p></body><br />
</html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2012/04/automating-ftp-tests-using-apache-mina/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Implement Generators In Java</title>
		<link>http://www.zoominfo.com/business/blog/2012/03/how-to-implement-generators-in-java-2/</link>
		<comments>http://www.zoominfo.com/business/blog/2012/03/how-to-implement-generators-in-java-2/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 20:13:52 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6326</guid>
		<description />
			<content:encoded><![CDATA[<style type="text/css"><!--/**
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 */
.java5  {font-family:monospace;color: #006; border: 1px solid #d0d0d0; background-color: #f0f0f0;}
.java5 a:link {color: #000060;}
.java5 a:hover {background-color: #f0f000;}
.java5 .imp {font-weight: bold; color: red;}
.java5 .kw1 {color: #000000;  font-weight: bold;}
.java5 .kw2 {color: #000000; font-weight: bold;}
.java5 .kw3 {color: #006600; font-weight: bold;}
.java5 .kw4 {color: #006600; font-weight: bold;}
.java5 .kw5 {color: #003399; font-weight: bold;}
.java5 .kw6 {color: #003399; font-weight: bold;}
.java5 .kw7 {color: #003399; font-weight: bold;}
.java5 .kw8 {color: #003399; font-weight: bold;}
.java5 .kw9 {color: #003399; font-weight: bold;}
.java5 .kw10 {color: #003399; font-weight: bold;}
.java5 .kw11 {color: #003399; font-weight: bold;}
.java5 .kw12 {color: #003399; font-weight: bold;}
.java5 .kw13 {color: #003399; font-weight: bold;}
.java5 .kw14 {color: #003399; font-weight: bold;}
.java5 .kw15 {color: #003399; font-weight: bold;}
.java5 .kw16 {color: #003399; font-weight: bold;}
.java5 .kw17 {color: #003399; font-weight: bold;}
.java5 .kw18 {color: #003399; font-weight: bold;}
.java5 .kw19 {color: #003399; font-weight: bold;}
.java5 .kw20 {color: #003399; font-weight: bold;}
.java5 .kw21 {color: #003399; font-weight: bold;}
.java5 .kw22 {color: #003399; font-weight: bold;}
.java5 .kw23 {color: #003399; font-weight: bold;}
.java5 .kw24 {color: #003399; font-weight: bold;}
.java5 .kw25 {color: #003399; font-weight: bold;}
.java5 .kw26 {color: #003399; font-weight: bold;}
.java5 .kw27 {color: #003399; font-weight: bold;}
.java5 .kw28 {color: #003399; font-weight: bold;}
.java5 .kw29 {color: #003399; font-weight: bold;}
.java5 .kw30 {color: #003399; font-weight: bold;}
.java5 .kw31 {color: #003399; font-weight: bold;}
.java5 .kw32 {color: #003399; font-weight: bold;}
.java5 .kw33 {color: #003399; font-weight: bold;}
.java5 .kw34 {color: #003399; font-weight: bold;}
.java5 .kw35 {color: #003399; font-weight: bold;}
.java5 .kw36 {color: #003399; font-weight: bold;}
.java5 .kw37 {color: #003399; font-weight: bold;}
.java5 .kw38 {color: #003399; font-weight: bold;}
.java5 .kw39 {color: #003399; font-weight: bold;}
.java5 .kw40 {color: #003399; font-weight: bold;}
.java5 .kw41 {color: #003399; font-weight: bold;}
.java5 .kw42 {color: #003399; font-weight: bold;}
.java5 .kw43 {color: #003399; font-weight: bold;}
.java5 .kw44 {color: #003399; font-weight: bold;}
.java5 .kw45 {color: #003399; font-weight: bold;}
.java5 .kw46 {color: #003399; font-weight: bold;}
.java5 .kw47 {color: #003399; font-weight: bold;}
.java5 .kw48 {color: #003399; font-weight: bold;}
.java5 .kw49 {color: #003399; font-weight: bold;}
.java5 .kw50 {color: #003399; font-weight: bold;}
.java5 .kw51 {color: #003399; font-weight: bold;}
.java5 .kw52 {color: #003399; font-weight: bold;}
.java5 .kw53 {color: #003399; font-weight: bold;}
.java5 .kw54 {color: #003399; font-weight: bold;}
.java5 .kw55 {color: #003399; font-weight: bold;}
.java5 .kw56 {color: #003399; font-weight: bold;}
.java5 .kw57 {color: #003399; font-weight: bold;}
.java5 .kw58 {color: #003399; font-weight: bold;}
.java5 .kw59 {color: #003399; font-weight: bold;}
.java5 .kw60 {color: #003399; font-weight: bold;}
.java5 .kw61 {color: #003399; font-weight: bold;}
.java5 .kw62 {color: #003399; font-weight: bold;}
.java5 .kw63 {color: #003399; font-weight: bold;}
.java5 .kw64 {color: #003399; font-weight: bold;}
.java5 .kw65 {color: #003399; font-weight: bold;}
.java5 .kw66 {color: #003399; font-weight: bold;}
.java5 .kw67 {color: #003399; font-weight: bold;}
.java5 .kw68 {color: #003399; font-weight: bold;}
.java5 .kw69 {color: #003399; font-weight: bold;}
.java5 .kw70 {color: #003399; font-weight: bold;}
.java5 .kw71 {color: #003399; font-weight: bold;}
.java5 .kw72 {color: #003399; font-weight: bold;}
.java5 .kw73 {color: #003399; font-weight: bold;}
.java5 .kw74 {color: #003399; font-weight: bold;}
.java5 .kw75 {color: #003399; font-weight: bold;}
.java5 .kw76 {color: #003399; font-weight: bold;}
.java5 .kw77 {color: #003399; font-weight: bold;}
.java5 .kw78 {color: #003399; font-weight: bold;}
.java5 .kw79 {color: #003399; font-weight: bold;}
.java5 .kw80 {color: #003399; font-weight: bold;}
.java5 .kw81 {color: #003399; font-weight: bold;}
.java5 .kw82 {color: #003399; font-weight: bold;}
.java5 .kw83 {color: #003399; font-weight: bold;}
.java5 .kw84 {color: #003399; font-weight: bold;}
.java5 .kw85 {color: #003399; font-weight: bold;}
.java5 .kw86 {color: #003399; font-weight: bold;}
.java5 .kw87 {color: #003399; font-weight: bold;}
.java5 .kw88 {color: #003399; font-weight: bold;}
.java5 .kw89 {color: #003399; font-weight: bold;}
.java5 .kw90 {color: #003399; font-weight: bold;}
.java5 .kw91 {color: #003399; font-weight: bold;}
.java5 .kw92 {color: #003399; font-weight: bold;}
.java5 .kw93 {color: #003399; font-weight: bold;}
.java5 .kw94 {color: #003399; font-weight: bold;}
.java5 .kw95 {color: #003399; font-weight: bold;}
.java5 .kw96 {color: #003399; font-weight: bold;}
.java5 .kw97 {color: #003399; font-weight: bold;}
.java5 .kw98 {color: #003399; font-weight: bold;}
.java5 .kw99 {color: #003399; font-weight: bold;}
.java5 .kw100 {color: #003399; font-weight: bold;}
.java5 .kw101 {color: #003399; font-weight: bold;}
.java5 .kw102 {color: #003399; font-weight: bold;}
.java5 .kw103 {color: #003399; font-weight: bold;}
.java5 .kw104 {color: #003399; font-weight: bold;}
.java5 .kw105 {color: #003399; font-weight: bold;}
.java5 .kw106 {color: #003399; font-weight: bold;}
.java5 .kw107 {color: #003399; font-weight: bold;}
.java5 .kw108 {color: #003399; font-weight: bold;}
.java5 .kw109 {color: #003399; font-weight: bold;}
.java5 .kw110 {color: #003399; font-weight: bold;}
.java5 .kw111 {color: #003399; font-weight: bold;}
.java5 .kw112 {color: #003399; font-weight: bold;}
.java5 .kw113 {color: #003399; font-weight: bold;}
.java5 .kw114 {color: #003399; font-weight: bold;}
.java5 .kw115 {color: #003399; font-weight: bold;}
.java5 .kw116 {color: #003399; font-weight: bold;}
.java5 .kw117 {color: #003399; font-weight: bold;}
.java5 .kw118 {color: #003399; font-weight: bold;}
.java5 .kw119 {color: #003399; font-weight: bold;}
.java5 .kw120 {color: #003399; font-weight: bold;}
.java5 .kw121 {color: #003399; font-weight: bold;}
.java5 .kw122 {color: #003399; font-weight: bold;}
.java5 .kw123 {color: #003399; font-weight: bold;}
.java5 .kw124 {color: #003399; font-weight: bold;}
.java5 .kw125 {color: #003399; font-weight: bold;}
.java5 .kw126 {color: #003399; font-weight: bold;}
.java5 .kw127 {color: #003399; font-weight: bold;}
.java5 .kw128 {color: #003399; font-weight: bold;}
.java5 .kw129 {color: #003399; font-weight: bold;}
.java5 .kw130 {color: #003399; font-weight: bold;}
.java5 .kw131 {color: #003399; font-weight: bold;}
.java5 .kw132 {color: #003399; font-weight: bold;}
.java5 .kw133 {color: #003399; font-weight: bold;}
.java5 .kw134 {color: #003399; font-weight: bold;}
.java5 .kw135 {color: #003399; font-weight: bold;}
.java5 .kw136 {color: #003399; font-weight: bold;}
.java5 .kw137 {color: #003399; font-weight: bold;}
.java5 .kw138 {color: #003399; font-weight: bold;}
.java5 .kw139 {color: #003399; font-weight: bold;}
.java5 .kw140 {color: #003399; font-weight: bold;}
.java5 .kw141 {color: #003399; font-weight: bold;}
.java5 .kw142 {color: #003399; font-weight: bold;}
.java5 .kw143 {color: #003399; font-weight: bold;}
.java5 .kw144 {color: #003399; font-weight: bold;}
.java5 .kw145 {color: #003399; font-weight: bold;}
.java5 .kw146 {color: #003399; font-weight: bold;}
.java5 .kw147 {color: #003399; font-weight: bold;}
.java5 .kw148 {color: #003399; font-weight: bold;}
.java5 .kw149 {color: #003399; font-weight: bold;}
.java5 .kw150 {color: #003399; font-weight: bold;}
.java5 .kw151 {color: #003399; font-weight: bold;}
.java5 .kw152 {color: #003399; font-weight: bold;}
.java5 .kw153 {color: #003399; font-weight: bold;}
.java5 .kw154 {color: #003399; font-weight: bold;}
.java5 .kw155 {color: #003399; font-weight: bold;}
.java5 .kw156 {color: #003399; font-weight: bold;}
.java5 .kw157 {color: #003399; font-weight: bold;}
.java5 .kw158 {color: #003399; font-weight: bold;}
.java5 .kw159 {color: #003399; font-weight: bold;}
.java5 .kw160 {color: #003399; font-weight: bold;}
.java5 .kw161 {color: #003399; font-weight: bold;}
.java5 .kw162 {color: #003399; font-weight: bold;}
.java5 .kw163 {color: #003399; font-weight: bold;}
.java5 .kw164 {color: #003399; font-weight: bold;}
.java5 .kw165 {color: #003399; font-weight: bold;}
.java5 .kw166 {color: #003399; font-weight: bold;}
.java5 .co1 {color: #666666; font-style: italic;}
.java5 .co2 {color: #006699;}
.java5 .co3 {color: #008000; font-style: italic; font-weight: bold;}
.java5 .coMULTI {color: #666666; font-style: italic;}
.java5 .es0 {color: #000099; font-weight: bold;}
.java5 .br0 {color: #009900;}
.java5 .sy0 {color: #339933;}
.java5 .st0 {color: #0000ff;}
.java5 .nu0 {color: #cc66cc;}
.java5 .me1 {color: #006633;}
.java5 .me2 {color: #006633;}
.java5 span.xtra { display:block; }
--!></style>
<p>If you&#8217;ve ever used more than one programming language, you&#8217;ve probably found that &#8211; as you switch between them &#8211; there&#8217;s usually some feature that you&#8217;ve left behind that you really miss. It could be a particular class, syntactic sugar, or language construct that you just can&#8217;t do without. When I joined Zoom some 5+ years ago, I went from doing development primarily in Python and C# to doing development primarily in Java. One of the little things I missed from those languages was generators.</p>
<p>Generators are a simple but powerful tool for creating iterators. They are written like regular functions but use a &#8220;yield&#8221; statement whenever they want to return data. Each time next() is called in your for-each loop, control passes to the generator and it resumes right where it left off &#8211; its local variables and execution state are automatically saved between calls. The generator returns control back to your loop when it &#8220;yields&#8221; the next value in the iteration.</p>
<p>Using generators &#8211; like iterators &#8211; can confer some nice performance benefits. This performance boost is the result of the lazy (on-demand) generation of values, which translates to lower memory usage. Furthermore, we do not need to wait until all the elements have been generated before we start to use them.</p>
<p>It&#8217;s important to note that anything that can be done with generators can also be done with iterators. What makes generators so nice &#038; compact is that the iterator(), hasNext() and next() methods are all created automatically for you. This helps make generators easier to write and much clearer than an iterator-based approach. You don&#8217;t have to write a ton of boilerplate and a mini state machine just to keep track of your progress.</p>
<p>By now, you&#8217;ve probably picked up that Java doesn&#8217;t have generators. Worse still, Java (the language, not the JVM) doesn&#8217;t have built-in support for continuations &#8211; a useful building block for implementing generators (though there are some 3rd-party add-ons like <a href="http://commons.apache.org/sandbox/javaflow/">Apache Javaflow</a> that implement them via bytecode manipulation). Fortunately, not all is lost. A bit of Googling turned up an excellent <a href="http://jimblackler.net/blog/?p=61">blog post</a> by Jim Blackler who had implemented a Yield/Return framework in Java. After ironing out a few bugs in the framework (and passing those patches back to Jim), we at Zoom adopted it for use in our production environment.</p>
<p>Jim&#8217;s framework is based on a traditional producer/consumer model. In it, two threads effectively do the work of one. Control passes between the &#8220;worker&#8221; thread (which computes your iteration&#8217;s values) and the managing thread (which implements the <a href="http://docs.oracle.com/javase/6/docs/api/java/util/Iterator.html">java.util.Iterator</a> logic). Each invocation of &#8220;Iterator.next()&#8221; causes the worker thread to wake up and compute the next result, which it puts into a Java <a href="http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/SynchronousQueue.html">SynchronousQueue</a>. The worker thread goes back to sleep and the manager thread pops the queue, returning the newly-computed value to your &#8220;for&#8221; loop.</p>
<p>By itself, Jim&#8217;s framework got us lazy-computation and a more natural programming model than straight Java Iterators, which was a huge improvement. But much like iterators, it required writing a lot of boilerblate code. Writing anything in Java requires writing a lot of boilerplate, but we strive to keep that to a minimum. To solve this, we wrote a really simple &#8220;Generator&#8221; base class that is easily extensible. It implements the <a href="http://docs.oracle.com/javase/6/docs/api/java/lang/Iterable.html">Iterable</a> interface, so you can use Generators wherever you would use a Java 1.5-style &#8220;for-each&#8221; loop. All it requires is that you implement your business logic inside of a &#8220;run()&#8221; method, return values via its &#8220;yield&#8221; method, and it figures out the rest for you. I&#8217;ve included the framework (both Jim&#8217;s and Zoom&#8217;s code) for <a href="https://github.com/domlachowicz/java-generators" target="_blank">download here</a>, and I&#8217;ve included some illustrative code samples below.</p>
<p>In the following examples, you&#8217;ll see how easy it is to implement Python&#8217;s numeric range() function and its string-reversing function using generators, just like the core Python library does. You can read up on the Python examples and more on generators <a href="http://wiki.python.org/moin/Generators">here</a>.</p>
<p align="right">-Dominic Lachowicz, <i>Director of Core Development</i></p>
<hr />
<div class="java5">&nbsp; &nbsp; <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Iterable.html"><span class="kw21">Iterable</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span> range<span class="br0">&#40;</span><span class="kw3">int</span> hi<span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> range<span class="br0">&#40;</span><span class="nu0">0</span>, hi<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Iterable.html"><span class="kw21">Iterable</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span> range<span class="br0">&#40;</span><span class="kw3">int</span> lo, <span class="kw3">int</span> hi<span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> range<span class="br0">&#40;</span>lo, hi, <span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Iterable.html"><span class="kw21">Iterable</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span> range<span class="br0">&#40;</span><span class="kw2">final</span> <span class="kw3">int</span> lo, <span class="kw2">final</span> <span class="kw3">int</span> hi, <span class="kw2">final</span> <span class="kw3">int</span> step<span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> <span class="kw2">new</span> Generator<span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw3">int</span> i = lo<span class="sy0">;</span> i <span class="sy0">!</span>= hi<span class="sy0">;</span> i += step<span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield<span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Iterable.html"><span class="kw21">Iterable</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Character.html"><span class="kw21">Character</span></a><span class="sy0">&gt;</span> reverse<span class="br0">&#40;</span><span class="kw2">final</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/CharSequence.html"><span class="kw21">CharSequence</span></a> string<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> <span class="kw2">new</span> Generator<span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Character.html"><span class="kw21">Character</span></a><span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw3">int</span> i : range<span class="br0">&#40;</span>string.<span class="me1">length</span><span class="br0">&#40;</span><span class="br0">&#41;</span> &#8211; <span class="nu0">1</span>, -<span class="nu0">1</span>, -<span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield<span class="br0">&#40;</span>string.<span class="me1">charAt</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw2">static</span> <a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Iterable.html"><span class="kw21">Iterable</span></a><span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span> firstn<span class="br0">&#40;</span><span class="kw2">final</span> <span class="kw3">int</span> n<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> <span class="kw2">new</span> Generator<span class="sy0">&lt;</span><a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Integer.html"><span class="kw21">Integer</span></a><span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @<a href="http://java.sun.com/j2se/1%2E5%2E0/docs/api/java/lang/Override.html"><span class="kw21">Override</span></a><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw3">void</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">int</span> num = <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>num <span class="sy0">&lt;</span> n<span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield<span class="br0">&#40;</span>num<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; num += <span class="nu0">1</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="br0">&#125;</span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2012/03/how-to-implement-generators-in-java-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ZoomInfo kicks off another year of events….Vegas-style!</title>
		<link>http://www.zoominfo.com/business/blog/2012/02/zoominfo-kicks-off-another-year-of-events%e2%80%a6-vegas-style/</link>
		<comments>http://www.zoominfo.com/business/blog/2012/02/zoominfo-kicks-off-another-year-of-events%e2%80%a6-vegas-style/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 16:32:48 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6302</guid>
		<description><![CDATA[ZoomInfo is extremely excited to jump-start February with our first tradeshow appearance of the year at Marketing Sherpa’s E-mail Summit in Las Vegas.  And of course, it’s only normal for us to give away awesome prizes for stopping by our &#8230; <a href="http://www.zoominfo.com/business/blog/2012/02/zoominfo-kicks-off-another-year-of-events%e2%80%a6-vegas-style/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>ZoomInfo is extremely excited to jump-start February with our first tradeshow appearance of the year at <a href="http://www.meclabs.com/training/marketing-summit/email-summit-2012?9641">Marketing Sherpa’s E-mail Summit</a> in Las Vegas.  And of course, it’s only normal for us to give away awesome prizes for stopping by our booth.  Fill out a survey or take a demo and you’re automatically a winner of one of five Vegas-style prizes including a Kindle, $25 AMEX Gift Cards, 1,000 Free Contacts, E-mail Address Validation up to 2,500 contacts and 2 tickets to Cirque LOVE with dinner at Kokomos.  Everyone’s a winner in Vegas baby!</p>
<p>Not attending next week’s show? Find us at our second stop in Hollywood, FL on Feb 22-24 for DMA’s <a href="http://www.the-dma.org/conferences/emailevolution/">E-mail Evolution Conference</a> at the Westin Diplomat Resort &amp; Spa.  We’ll be showing off our award-winning Pro solution and offering fun giveaways including $100 iTunes Gift Cards, Kindles, $25 AMEX Gift Cards and thousands of free contacts straight from the ZoomInfo database.</p>
<p>Want to schedule a meet up with one of our data experts?  <a href="http://www.zoominfo.com/business/about/events.html">Fill out this form</a></p>
<p>We hope to see you soon!  Viva Las Vegas!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2012/02/zoominfo-kicks-off-another-year-of-events%e2%80%a6-vegas-style/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ZoomInfo Upcoming Events &amp; Announcements</title>
		<link>http://www.zoominfo.com/business/blog/2011/12/zoominfo-upcoming-events-announcements/</link>
		<comments>http://www.zoominfo.com/business/blog/2011/12/zoominfo-upcoming-events-announcements/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 04:17:35 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6254</guid>
		<description><![CDATA[First and foremost, we begin by sending a bold &#8216;THANK YOU’ to our ZoomInfo team, clients, supporters, and online followers!   In honor of both our outstanding year and recent announcement of being a CODiE Award Finalist, we decided to kick &#8230; <a href="http://www.zoominfo.com/business/blog/2011/12/zoominfo-upcoming-events-announcements/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>First and foremost, we begin by sending a bold<strong> </strong>&#8216;<strong>THANK YOU</strong><em>’</em> to our ZoomInfo team, clients, supporters, and <a href="http://www.twitter.com/zoominfo">online followers</a>!   In honor of both our outstanding year and recent announcement of being a <a href="http://www.siia.net/codies/2012/finalist_detail.asp?id=11">CODiE Award Finalist</a>, we decided to kick off our holiday festivities popping bottles and toasting to all our supporters.  Cheers, this one&#8217;s for you!</p>
<p>Inspired with this support, we decided to return the favor by donating coats, clothes, toys, and more to several charities including <a href="http://www.antons.com/cfk/index.php "><strong>Coats for Kids</strong></a> and<strong> <a href="http://www.toysfortots.org/default.asp">The Official U.S. Marine Corps Toys for Tots Foundation</a></strong>.  Please join us in this effort!</p>
<p>Continuing on high spirits, we’re currently preparing for our end of year events, including both our annual company pot luck and New Year’s Party!   Anticipating the assortment of homemade dishes, we&#8217;ve been prepared to eat <em>since </em>Thanksgiving! Well, who wouldn’t when <em>spoiled</em> with amazing bakers like Kelly G., who we believe to be an Account Representative during the day and a baker during the night!  <a href="http://a3.sphotos.ak.fbcdn.net/hphotos-ak-snc7/393119_293519724005483_109325735758217_1105042_170898960_n.jpg">Have you seen</a> her Halloween cake! Sweet, isn’t it? Okay! Okay! Enough with our holiday celebrations and on to our industry events!</p>
<p>Last week our Director of Sales, Mark Ruthfield held an engaging speaking session at <a href="http://www.aa-isp.org/inside-sales-boston.php">AA-ISP’s Boston Conference</a> attendees, spreading his wealth of sales knowledge and company updates  to other sales leaders.  One of the events he mentioned was our upcoming  <strong><a href="http://go.zoominfo.com/sales-dream-team-recruiting-event">Sales Dream Team Recruiting Event</a></strong>, welcoming potential entry level candidates for our sales and marketing team.  If you know anyone suited for that event, give them the gift of opportunity and send them our way!</p>
<p>No, the excitement doesn&#8217;t stop there! Continuing this eventful month, our marketing team has coordinated <em>not</em> one but <strong>TWO</strong> <a href="http://www.zoominfo.com/business/resources/webinars.html">webinars</a> in <em>just </em>one week!  Our first webinar, &#8220;Pro Day,&#8221; uncovered several tips and tricks for generating new leads with <a href="http://www.zoominfo.com/business/products/pro.html">ZoomInfo Pro</a>.  ‘Tis the season of giving all right!   All attendees left with a FREE 24-hour exclusive pass to our tool topped off with a <strong>BONUS</strong> invitation to today’s <a href="https://www2.gotomeeting.com/register/943599570?utm_source=sm&amp;utm_medium=sm&amp;utm_campaign=Social%2BMedia">webinar featuring Recruiting Guru</a>, Chris Murdock, who will be <em>directly</em> responding to questions from recruiting professionals of all industries.  No worries though, with luck and support for reading our blog, you have just been <a href="https://www2.gotomeeting.com/register/943599570?utm_source=sm&amp;utm_medium=sm&amp;utm_campaign=Social%2BMedia">invited!</a></p>
<p>Again, we love our supporters and we appreciate the continuous belief in our services!  To <em>wrap</em> things up, we’ve included the most recent picture of our ZoomInfo team, taken <em>just</em> a couple days ago!</p>
<p><a href="http://lxscms01.xoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/12/zoominfo-team-photo-blog1.jpg"><img class="aligncenter size-full wp-image-6256" title="Zoom Team" src="http://lxscms01.xoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/12/zoominfo-team-photo-blog1.jpg" alt="" width="500" height="333" /></a>Don&#8217;t forget to<a href="http://twitter.com/zoominfo"><span style="text-decoration: underline;"> Follow Us</span></a> for live announcements, <a href="http://facebook.com/ZoomInformation"><span style="text-decoration: underline;">Like Us</span></a> for access to event photos, and <a href="http://zoominfo.com/linkedin"><span style="text-decoration: underline;">Join</span> </a>us on LinkedIn!  We hope you enjoy the rest of the week and be sure to revisit our blog!</p>
<p>-<em>Catherine Heng</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2011/12/zoominfo-upcoming-events-announcements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fantastic Four Ways to Generate B2B Leads</title>
		<link>http://www.zoominfo.com/business/blog/2011/12/fantastic-four-to-generate-new-b2b-leads/</link>
		<comments>http://www.zoominfo.com/business/blog/2011/12/fantastic-four-to-generate-new-b2b-leads/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 20:16:20 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6233</guid>
		<description><![CDATA[Hands raised if you want new leads!  I repeat, hands raised if you want new leads!! I’m guessing those hands raised belong to your sales department? Oh marketing, do you feel that pressure or jeez, that stink?  We’ve all sensed &#8230; <a href="http://www.zoominfo.com/business/blog/2011/12/fantastic-four-to-generate-new-b2b-leads/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hands raised if you want new leads!  I repeat, hands raised if you  want new leads!! I’m guessing those hands raised belong to your sales  department?<em> Oh marketing</em>, do you feel that pressure or <em>jeez</em>, that stink?  We’ve all sensed that at one point in time or another but cheer up, <strong><span style="text-decoration: underline;">You</span> <span style="text-decoration: underline;">Are</span> <span style="text-decoration: underline;">Not</span> <span style="text-decoration: underline;">Alone</span>!</strong></p>
<p>Zooming to the rescue, we are here to lend you a hand, giving you our <strong><span style="text-decoration: underline;">FANTASTIC</span></strong><span style="text-decoration: underline;"> <strong>FOUR</strong></span> secrets to generating new B2B leads!</p>
<ol>
<li><strong>Connections</strong>:      It’s not about <em>what </em>you know but <em>WHO </em>you  know!        Business flourishes at a fast pace most effectively  through referrals and      viral marketing, all part of a heavy cost  saving strategy for<em> winning </em>new      business.   Manage those  connections through social media      (Twitter, Facebook, and LinkedIn)  to increase your lead generation      initiatives in a <strong><em>fast</em></strong>, <strong><em>free</em></strong>, <em>and <strong>fun</strong></em><strong> </strong>way!   Do I smell a New Year’s Resolution? Free the social      butterfly in  you and make connections, connection, and let&#8217;s not forget,      more  connections!</li>
<li><strong>E-mail Marketing:</strong> Saving your company&#8217;s time and money, B2B  e-mail marketing is the new      direct mail.  With the rising  popularity in this effort, our clients      are leveraging ZoomInfo&#8217;s  data services (<a href="http://www.zoominfo.com/business/blog/2011/09/introducing-zoominfo-email-validation/?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+ZoominfoBlogBusinessDataManagement+%28ZoomInfo+Blog+%C2%BB+Business+Data+Management%29">e-mail validation</a>, <span style="text-decoration: underline;"> </span><a href="http://www.zoominfo.com/business/products/data-services.html">marketing lists</a>, and <a href="http://www.zoominfo.com/business/products/data-services.html">data append services</a>)  to successfully      execute targeted e-mail marketing campaigns,  filling their bucket of leads.  Has your company checked out ZoomInfo&#8217;s  B2B      database?  <strong>Do it</strong>.  <em>I dare you!</em></li>
<li><strong>Content:</strong> If your products are as good as you claim than you’d  be an expert in your      industry.  This trust and credibility can be  easily established      through content marketing using blogs,  newsletters, webinars, whitepapers,      and e-books!  Utilizing this  tactic, companies such as  <a href="http://www.zappos.com/" target="_blank">Zappos</a>,      <a href="http://www.hubspot.com/" target="_blank">Hubspot</a>,      and <a href="http://www.forrester.com/" target="_blank">Forrester</a> have been able to convert      their large audience of readers (<strong>connections: tip #1</strong>) into new      leads.</li>
<li><strong>Search Engine Optimization</strong>: True to the fact that I am  extremely gullible, I      believe your products are as good as you say,  though that would mean      I  <em>recognize </em>your products.  Used to  generate new leads and      increase brand recognition, Search Engine  Optimization Marketing along      with banner ads are both popular  strategies to pocket new      leads.  Now that&#8217;s a &#8220;win-win&#8221;       situation!</li>
</ol>
<p>How are these tips connected?  By leveraging landing pages, you&#8217;ll  transform viewers into leads with limited to no cost.  Now marketing, do you <em>still </em>feel that pressure or <em>jeez</em>, that stink? Well, getting rid of both requires taking <strong>action</strong>! <a href="http://go.zoominfo.com/data-consultation?utm_source=sm&amp;utm_medium=sm&amp;utm_campaign=social%2Bmedia"> Speak with us today</a> to determine how our products can support your future lead generation initiatives.</p>
<p>Best of Luck!</p>
<p><em>-Catherine Heng</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2011/12/fantastic-four-to-generate-new-b2b-leads/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hiring! Hiring! Read all about it!</title>
		<link>http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/</link>
		<comments>http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 05:16:42 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6217</guid>
		<description><![CDATA[While the United States unemployment rate has plumped to an eye-opening rate of about 9.1%, ZoomInfo is welcoming new talent in all departments including engineering, sales, and marketing.  Yeah folks, you got it! We’re opening our glass doors to potential &#8230; <a href="http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>While the United States unemployment rate has plumped to an eye-opening rate of about 9.1%, ZoomInfo is <a href="http://www.zoominfo.com/business/about/careers.html">welcoming new talent</a> in all departments including engineering, sales, and marketing.  Yeah folks, you got it! We’re opening our glass doors to potential Zoomers which, who knows, could be YOU!</p>
<p>What’s all the hype with ZoomInfo?  Luckily for you, I’ve worked my way to veteran status, being able to give you a <strong>live</strong> testimonial of what’s <em>hot</em> at ZoomInfo.  Ouch, it burns!  With so many reasons to work at ZoomInfo, here are my <strong>FANTASTIC FOUR</strong>!</p>
<ul>
<li><strong>People</strong>:  Why wouldn’t you want to work with a diverse and exceptionally talented crowd of individuals?  With about 65 employees, we learn together, work together, and <em>even </em>share our special occasion with one another; births to weddings and plane rides to holidays.  Aww, it’s a <a href="http://www.facebook.com/media/albums/?id=109325735758217">Kodak moment</a>!</li>
<li><strong>Events</strong>:   With new volunteers every quarter, all Zoomers have the opportunity to plan <a href="http://www.facebook.com/media/albums/?id=109325735758217">company festivities</a>.  Hosting over a dozen <a href="http://www.facebook.com/media/set/?set=a.294601333897322.82515.109325735758217&amp;type=1">company events</a> this year, we&#8217;ve attended two Boston sports games (Bruins and Red Sox), a golf tournament, <a href="http://www.facebook.com/media/set/?set=a.213172305373559.64395.109325735758217&amp;type=1">a bowling extravaganza</a>, and how remarkable, a couple of <a href="http://www.facebook.com/media/set/?set=a.194259090598214.52405.109325735758217&amp;type=1">themed company meetings</a>!  You know the saying, “Work hard, play hard?”  Well, we do too!</li>
<li><strong>Product</strong>:  Who isn’t aware of our award winning <a href="http://www.zoominfo.com/business/products/pro.html?utm_source=sm&amp;utm_medium=socialmedia&amp;utm_campaign=socialmedia">ZoomInfo Professional Solution</a>, <a href="http://www.zoominfo.com/business/products/data-services.html?utm_source=sm&amp;utm_medium=socialmedia&amp;utm_campaign=socialmedia">Data Services</a>, and our <strong>FREE</strong> <a href="http://go.zoominfo.com/ce-registration-sm3">Community Edition</a>? Thanks to our <a href="http://www.zoominfo.com/business/blog/2011/11/shine-on-leo/">Engineering Team</a>, our patent technology has a unique method of aggregating data, constantly keeps our database fresh and up-to-date.   Written with confidence and spoken truthfully, we love the quality of our data and we are<strong> POSITIVE</strong> you will too.</li>
<li><strong>Culture</strong>:  As vibrant as our snazzy new clocks and our orange and blue painted office, our culture is <strong>invigorating</strong>, <strong>exciting</strong>, and <strong>hip</strong>!  From Engineer’s Tech Fest to Sale’s Phone Blitz, we are constantly implementing new and fun ways to work together.   You can buy data and you can buy tools. Culture though, it’s priceless!</li>
</ul>
<p>Feel free to ZOOM-IN!</p>

<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/7/' title='7'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/7-150x150.jpg" class="attachment-thumbnail" alt="7" title="7" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/6/' title='6'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/6-150x150.jpg" class="attachment-thumbnail" alt="6" title="6" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/5/' title='5'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/5-150x150.jpg" class="attachment-thumbnail" alt="5" title="5" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/4/' title='4'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/4-150x150.jpg" class="attachment-thumbnail" alt="4" title="4" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/3/' title='3'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/3-150x150.jpg" class="attachment-thumbnail" alt="3" title="3" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/2/' title='2'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/2-150x150.jpg" class="attachment-thumbnail" alt="2" title="2" /></a>
<a href='http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/attachment/1/' title='1'><img width="150" height="150" src="http://www.zoominfo.com/business/components/com_wordpress/wp/wp-content/uploads/2011/11/1-150x150.jpg" class="attachment-thumbnail" alt="1" title="1" /></a>

<p>Check out <a href="http://www.zoominfo.com/business/about/careers.html">Careers at ZoomInfo</a> for all posted career positions.  <em>Already taken</em>?  No sweat!  <a href="https://twitter.com/zoominfo">Follow us</a> for future updates on new opportunities and open houses.  <em>Curious</em>? E-mail our Human Resources Manager, <a href="mailto:jennie.cohen@zoominfo.com">Jennie Cohen</a>, or  our Sales and Marketing Associate, <a href="mailto:catherine.heng@zoominfo.com">Me</a>!</p>
<p>Have a happy holiday and we hope to hear from you soon!</p>
<p><em>- Catherine Heng</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2011/11/hiring-hiring-read-all-about-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>4 Tips to Improving Your New Business Prospecting Efforts</title>
		<link>http://www.zoominfo.com/business/blog/2011/11/4-tips-to-improving-your-new-business-prospecting-efforts/</link>
		<comments>http://www.zoominfo.com/business/blog/2011/11/4-tips-to-improving-your-new-business-prospecting-efforts/#comments</comments>
		<pubDate>Thu, 17 Nov 2011 04:22:35 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6209</guid>
		<description><![CDATA[Welcome our guest blogger, Justin Champion, who is a Marketing Consultant with Search Mojo, a dedicated search engine marketing agency. He works with new prospects to determine the best fitting search marketing solution to achieve their goals. He also is &#8230; <a href="http://www.zoominfo.com/business/blog/2011/11/4-tips-to-improving-your-new-business-prospecting-efforts/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em><img class="alignleft" src="/business/images/stories/justin-champion.jpg" alt="" width="74" height="74" /></em><em>Welcome our guest blogger, Justin Champion, who is a Marketing Consultant with Search Mojo, a <a href="http://www.search-mojo.com/">dedicated search engine marketing agency</a>.   He works with new prospects to determine the best fitting search   marketing solution to achieve their goals. He also is a regular blogging   contributor to Search Mojo’s blog, <a href="http://blog.search-mojo.com/">Search Marketing Sage</a>.</em></p>
<p style="text-align: center;"><strong><span style="font-size: large;">4 Tips to Improving Your New Business Prospecting Efforts</span></strong></p>
<p>Prospecting for new business is not an easy task. Many get weighed  down by the thought of having to call someone they do not know, who is  not expecting their call. Ugh! However, for those of you who are new to  the game or looking to reevaluate your approach, here are four tips to  make your lead-generation process more effective.</p>
<p><strong>1. Set a simple goal for the initial call</strong></p>
<p>Do not just walk in expecting to wine and dine them. In order to gain  confidence with a prospect, you are going to need trust. This is not  something you are going to establish in the first two minutes. The goal  here should be <strong>identifying the decision maker</strong> and <strong>setting an appointment</strong>. You are not calling to sell them something. You’re calling to set up a time to discuss their <a href="http://blog.search-mojo.com/2011/07/29/3-main-points-to-focus-on-in-the-professional-sales-process/">needs and appropriate solutions</a>.</p>
<p>If they are not willing to <a href="http://www.salesgravy.com/Articles/activity/cold-calling-tip-to-eliminate-stress-and-failure.html">schedule an appointment with you</a>, then they are probably not going to buy from you either.</p>
<p><strong>2. Slow and steady wins the race</strong></p>
<p>HimynameisJustinandIworkwithSearchMojo… What? Don’t get your whole  speech out in one breath. Make sure to slow your pace and pronounce your  words in a clear and calm manner. If your approach sounds rushed, then  you are not setting a comfortable setting for a conversation. The last  thing you want to do is repeat yourself more than once—<strong><em>not very professional</em></strong>.</p>
<p><strong>3. Know your prospect</strong></p>
<p>Before you call, make sure you know:</p>
<ul>
<li>Name of company</li>
<li>Industry</li>
<li>Point of contact (use <a href="http://www.zoominfo.com/business/products/pro.html"> ZoomInfo Pro</a>!)</li>
<li>Why you’re calling</li>
</ul>
<p>The more you know about their industry—pain points, terminology,  etc—the better. Now, I am not saying that you have to perform in depth  research on each prospect, but it will help to work a vertical market  and get comfortable with the industry. Plus, what does it hurt to take a  look at their site before calling? The worst that can happen is you’ll <a href="http://www.zoominfo.com/business/blog/2011/05/the-roi-of-targeted-prospecting/">know more about their specific business offerings</a>.</p>
<p><strong>4. Make sure to follow up</strong></p>
<p>Over 90% of the time you will not reach the individual you want to  talk to. This is also where knowing what to say comes in handy—get ready  to make your first impression with a memorable voicemail.</p>
<p>However, a voicemail or leaving a message with the operator is not  going to cut it. If you really want to make a difference you have to  follow up. I do not recommend pestering them, calling every day, but do  not expect them to call you back because they <em>will</em> forget about you.</p>
<p>All-in-all, prospecting can be a rewarding experience with the right  preparation and attitude. The goal is not to get frustrated and focus in  for the long haul. Not everyone is going to want your services, but  there are people interested. It is your job to find them.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2011/11/4-tips-to-improving-your-new-business-prospecting-efforts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zoom Into ZoomInfo’s Engineering Department!</title>
		<link>http://www.zoominfo.com/business/blog/2011/11/shine-on-leo/</link>
		<comments>http://www.zoominfo.com/business/blog/2011/11/shine-on-leo/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 02:26:05 +0000</pubDate>
		<dc:creator>Catherine</dc:creator>
				<category><![CDATA[ZoomInfo News]]></category>

		<guid isPermaLink="false">http://lxscms01.xoominfo.com/business/blog/?p=6128</guid>
		<description><![CDATA[ZoomInfo relies on technology to create the world’s best directory of business and employee profiles, so we are always looking for new technologies and ways to exploit existing technologies to further that objective. As the Architect at ZoomInfo, I do &#8230; <a href="http://www.zoominfo.com/business/blog/2011/11/shine-on-leo/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" title="Leo Laferriere, Architect at ZoomInfo" src="/business/images/stories/laferrire.jpg" alt="" width="133" height="182" />ZoomInfo relies on technology to create the world’s best directory of business and employee profiles, so we are always looking for new technologies and ways to exploit existing technologies to further that objective. As the Architect at ZoomInfo, I do my best to keep up with new technologies – but there’s only so many hours in a day, and I certainly don’t have a monopoly on good ideas. (<em>Far from it!</em>)</p>
<p>From time to time, the ZoomInfo Engineering Team takes a break for a couple of days from normal project work (such as <a href="http://www.zoominfo.com/business/blog/author/plodine/">A Need To Scale: The Cassandra Project</a>) to explore <a href="http://www.zoominfo.com/business/blog/2011/06/the-importance-of-ideas/">new ideas</a> in a lively brainstorming session we call <em>IdeaFest</em>. Recently, I sponsored <em>TechFest </em>with this stated theme: “Demonstrate how new tools will allow you or ZoomInfo to do new tricks for the business or be more productive.” I provided a few examples and told everyone to be creative, <em>which was pretty much all the ground rules</em>!</p>
<p>About a week before TechFest, a whiteboard in the Engineering area was commandeered so team members could publicly announce the technology they planned to explore and new trick or productivity enhancement they thought it would enable. This got the conversation started and built excitement for the two-day TechFest.</p>
<p>On the morning of Day 1, all team members described their plans.  The resulting discussion enhanced the ideas and provided a mechanism for some team members to join forces.</p>
<p>Because we use Hadoop map-reduce and HDFS a lot, there were a number of people looking to investigate related technologies such as <a href="http://mahout.apache.org/">Mahout</a> for machine learning and data mining; <a href="http://www.cloudera.com/">Cloudera</a>’s distribution of Hadoop and related tools such as Scoop, Flume; and <a href="http://hive.apache.org/">Hive</a> for a scalable, query-able data warehouse. They created a company competitor classifier, a virtual Cloudera Hadoop cluster, and demonstrated potential ways we could use Scoop and Hive for ZoomInfo business on that cluster.</p>
<p>We use Cassandra for some of our large data stores, so engineers in both QA and development took the opportunity to investigate tools to query and export data in Cassandra to ease testing and debugging on those projects.  They looked at off-the-shelf tools and wrote a prototype to iterate over rows and extract key data.</p>
<p>Since we use SOLR as our search platform and have data in Cassandra, one engineer checked out <a href="https://github.com/tjake/Solandra/wiki">Solandra</a>, which integrates SOLR searching with Cassandra data. He learned that it has potential to provide SOLR searches updated immediately upon writes to Cassandra.</p>
<p>Some others investigated tools to increase productivity such as <a href="http://zeroturnaround.com/jrebel/">JRebel</a> for web development debugging, <a href="http://wiki.apidesign.org/wiki/Javaleon">Javeleon</a> for NetBeans development, and <a href="http://www.reviewboard.org/">Review Board</a> for web-based code reviews.</p>
<p>Another wrote a prototype with <a href="http://cxf.apache.org/">Apache CXF</a> to investigate its potential for a new API.</p>
<p>At the end of each day, all team members gave a demo or presented what they had done. To be fair, there were some other technologies that did not pan out – but that’s okay! By going through this exercise, we were able to determine that those technologies were not a good fit for now. Some technologies were deemed quite ready to proceed with at this time, so we’ll keep an eye on them as they mature. A handful of prototypes proved successful enough to be assigned to backlogs in specific projects for further investigation. Meanwhile, a couple of the productivity tools are already being worked into our development environment.</p>
<p>After TechFest, we returned to project work with some new tools to increase productivity, along with improved morale from exploring things that had been on our to-do lists. The Engineering Team is now highly motivated to leverage some of the identified technologies to do new tricks for the business.  Check back for future blog posts to see how we did that!</p>
<p>-Leo  Laferriere, <em>Web Architect</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zoominfo.com/business/blog/2011/11/shine-on-leo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

