<?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:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Sonatype Blog</title>
	
	<link>http://www.sonatype.com/people</link>
	<description>State-of-the-Art Build Production for the Modern Software Enterprise</description>
	<pubDate>Wed, 01 Jul 2009 00:49:20 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<geo:lat>37.380207</geo:lat><geo:long>-122.087871</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by/2.0/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/sonatype" type="application/rss+xml" /><feedburner:emailServiceId>sonatype</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Maven 2.2.0 Released!</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/4dhMwHe1h8M/</link>
		<comments>http://www.sonatype.com/people/2009/06/maven-220-released/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 00:49:18 +0000</pubDate>
		<dc:creator>john</dc:creator>
		
		<category><![CDATA[Community]]></category>

		<category><![CDATA[Maven]]></category>

		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2512</guid>
		<description><![CDATA[I&#8217;m pleased to announce that we at the Apache Maven project have released Maven 2.2.0. You should definitely give it a spin! Maven 2.1.0 was probably the most stable release we&#8217;ve ever done, in terms of the number of reported regressions. Maven 2.2.0 improves on this stability by fixing the few critical bugs that did [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m pleased to announce that we at the Apache Maven project have released Maven 2.2.0. You should definitely give it a spin! Maven 2.1.0 was probably the most stable release we&#8217;ve ever done, in terms of the number of reported regressions. Maven 2.2.0 improves on this stability by fixing the few critical bugs that did come up, along with adding some new functionality. You can grab the new version <a href="http://maven.apache.org/download.html">here</a>.</p>

<p>This release includes some important bugfixes and other improvements, including:</p>

<h2 id="removed_feature_from_210_that_resolved_expressions_in_version_elements_within_the_pom_on_installation_and_deployment">Removed feature from 2.1.0 that resolved expressions in version elements within the POM on installation and deployment.</h2>

<p>This code was causing inconsistencies between the POM that landed in the repository and artifacts that are derived from that POM. The most prominent example deals with the GPG plugin: since the POM was modified on deployment, the GPG signature generated during the build was useless. This by itself effectively made Maven 2.1.0 unusable for releases.</p>

<h2 id="switched_to_a_httpclient_based_wagon_implementation_for_reaching_http_repositories">Switched to a HttpClient-based wagon implementation for reaching HTTP repositories.</h2>

<p>This is crucial for people sending long passwords, since the HttpUrlConnection-driven wagon did not-nice things with BASIC authentication headers when the password was very long&#8230;it line-wrapped the Base-64 header value, rendering the HTTP request invalid. In addition, HttpClient offers a wide range of options for configuration over HttpUrlConnection.</p>

<h2 id="new_default_execution_ids_for_goals_bound_from_the_default_lifecycle_mapping_and_those_invoked_from_the_command_line">New default execution IDs for goals bound from the default lifecycle mapping and those invoked from the command line.</h2>

<p>Previously, the only way to configure plugins that were used from the command line was to put the configuration options into the plugin-level configuration. This meant that it was impossible to separate CLI-oriented configuration settings from those used in goals that were bound to the lifecycle. Now, you can simply use an execution block with an id of <code>default-cli</code> to compartmentalize CLI-specific options. </p>

<p>Likewise, Maven 2.1.0 forces users to add configuration at the plugin level for any goals bound to the build via default lifecycle mapping. This could be particularly troublesome when you had multiple goals from a single plugin bound in via lifecycle mapping, and needed to respecify the same configuration option differently for the different goals. For instance, using different includes or excludes between the <code>compiler:compile</code> and <code>compiler:testCompile</code> goal executions was basically impossible. In Maven 2.2.0, you can use executions with the new per-goal default execution-Ids. For the compiler example, you can use <code>default-compile</code> and <code>default-testCompile</code>, respectively, to separate configurations for these two default goal executions.</p>

<h2 id="java_15_is_now_a_requirement">Java 1.5+ is now a requirement.</h2>

<p>Maven 2.2.0 upgrades the Java requirement to 1.5 or later. This allows us to finally start making the migration onto the Java5 generics syntax, and other nice little perks that come with a less archaic version of Java.</p>

<h2 id="8230and_more8230">&#8230;and more&#8230;</h2>

<p>For the full list of updates, see the <a href="http://maven.apache.org/release-notes.html">Release Notes</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=4dhMwHe1h8M:3mr7DmG6-KY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=4dhMwHe1h8M:3mr7DmG6-KY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=4dhMwHe1h8M:3mr7DmG6-KY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=4dhMwHe1h8M:3mr7DmG6-KY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=4dhMwHe1h8M:3mr7DmG6-KY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=4dhMwHe1h8M:3mr7DmG6-KY:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/4dhMwHe1h8M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/maven-220-released/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/maven-220-released/</feedburner:origLink></item>
		<item>
		<title>Integration Tests with Maven (Part 2): Test Coverage Reports</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/KXgBVUN0VPU/</link>
		<comments>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-2-test-coverage-reports/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 18:05:17 +0000</pubDate>
		<dc:creator>velo</dc:creator>
		
		<category><![CDATA[How-To]]></category>

		<category><![CDATA[Maven]]></category>

		<category><![CDATA[emma]]></category>

		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2475</guid>
		<description><![CDATA[In the previous article, we demonstrated one way of running integration tests with Maven.  In this article, we will demonstrate how to measure the test coverage of both integration and unit tests.



We will be using Emma to measure and report the coverage.    EMMA is an open-source toolkit for measuring and reporting [...]]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-1-failsafe-plugin/">previous article</a>, we demonstrated one way of running integration tests with Maven.  In this article, we will demonstrate how to measure the test coverage of both integration and unit tests.</p>

<p><span id="more-2475"></span></p>

<p>We will be using Emma to measure and report the coverage.    EMMA is an open-source toolkit for measuring and reporting Java code coverage.</p>

<h3>Unit test coverage</h3>

<p>Let&#8217;s start by generating a coverage report for unit tests only. This will require 2 new plugins to be added to our pom.  The first one:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>37
38
39
40
41
42
43
44
45
46
47
48
49
</pre></td><td class="code"><pre class="xml xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.sonatype.maven.plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>emma-maven-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>process-classes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>instrument<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<p>This plugin will instrument classes at target/generated-class/emma/classes, this won&#8217;t change the original classes at target/classes.   Then, we must tell surefire plugin to look for classes at new location:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>51
52
53
54
55
56
57
58
</pre></td><td class="code"><pre class="xml xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.maven.plugins<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-surefire-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>2.4.3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;classesDirectory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${project.build.directory}/generated-classes/emma/classes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/classesDirectory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<p>At this point, we do 50% of code coverage. Mainly because the psvm ( public static void main ) is never executed.</p>

<p>Here is the EMMA text report.  Emma does produce xml and html reports in addition to this simple text report:</p>


<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">[EMMA v2.0.5312 report, generated Fri Jun 12 15:43:28 BRT 2009]
-------------------------------------------------------------------------------
OVERALL COVERAGE SUMMARY:
&nbsp;
[class, %]	[method, %]	[block, %]	[line, %]	[name]
100% (1/1)	67%  (2/3)!	56%  (10/18)!	50%  (4/8)!	all classes</pre></div></div>


<p><b>Note:</b> at this point no report is generated, we will configure report generation after integration tests coverage reports are in place.   Once you run Surefire, you may notice the <em>coverage.ec</em> in the project root directory.  This file contains the coverage result in a binary format used by Emma.</p>

<h3>Integration test coverage</h3>

<p>So far, we have the unit tests results.  As I demonstrated in the previous article in this series,  the integration tests need the project artifact to run, so, we need to instrument this jar in order to get coverage result on ITs.  Let&#8217;s see the pom:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>plugin<span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>groupId<span style="color: #339933;">&gt;</span>org.<span style="color: #006633;">sonatype</span>.<span style="color: #006633;">maven</span>.<span style="color: #006633;">plugin</span><span style="color: #339933;">&lt;/</span>groupId<span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>artifactId<span style="color: #339933;">&gt;</span>emma4it<span style="color: #339933;">-</span>maven<span style="color: #339933;">-</span>plugin<span style="color: #339933;">&lt;/</span>artifactId<span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>version<span style="color: #339933;">&gt;</span><span style="color: #cc66cc;">1.3</span><span style="color: #339933;">&lt;/</span>version<span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>executions<span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;</span>execution<span style="color: #339933;">&gt;</span>
      <span style="color: #339933;">&lt;</span>id<span style="color: #339933;">&gt;</span>instrument<span style="color: #339933;">&lt;/</span>id<span style="color: #339933;">&gt;</span>
      <span style="color: #339933;">&lt;</span>goals<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>goal<span style="color: #339933;">&gt;</span>instrument<span style="color: #339933;">-</span>project<span style="color: #339933;">-</span>artifact<span style="color: #339933;">&lt;/</span>goal<span style="color: #339933;">&gt;</span>
      <span style="color: #339933;">&lt;/</span>goals<span style="color: #339933;">&gt;</span>
      <span style="color: #339933;">&lt;</span>configuration<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>appendEmma<span style="color: #339933;">&gt;</span>true<span style="color: #339933;">&lt;/</span>appendEmma<span style="color: #339933;">&gt;</span>
      <span style="color: #339933;">&lt;/</span>configuration<span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;/</span>execution<span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;/</span>executions<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>plugin<span style="color: #339933;">&gt;</span></pre></td></tr></table></div>


<p>Note that is using a different plugin: emma4it-maven-plugin.  This plugin provides some additional goals for instrumenting integrations tests.    For this project we use <strong>instrument-project-artifact</strong> goal. This goal will add Emma instrumentation into the project jar.  This is specific to tests running on integration-test phase, because it does requires that the packaged artifact be instrumented.</p>

<p>There is also the configuration <em>appendEmma</em>.  When true, this goal will shade the Emma jar into the instrumented jar.  This is very useful to test jars that will be launched from command line, like this project.</p>


<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">[EMMA v2.0.5312 report, generated Fri Jun 12 16:05:45 BRT 2009]
-------------------------------------------------------------------------------
OVERALL COVERAGE SUMMARY:
&nbsp;
[class, %]	[method, %]	[block, %]	[line, %]	[name]
100% (1/1)	100% (3/3)	89%  (16/18)	88%  (7/8)	all classes</pre></div></div>


<p>At this point we have a very decent code coverage, almost 90%, 7 of 8 lines of code, and on this project it is not possible to get 8/8.  And why is that? System.exit(). when this line is invoked nothing else is executed, that includes Emma instrumented code, so Emma won&#8217;t be able to know if System.exit() was executed, our integration tests catch that, because we check the exit code of the process, but Emma can&#8217;t do the same.</p>

<h3>Test Coverage Report</h3>

<p>At this point we have all coverage data stored at coverage.ec, in Emma binary format.  Let&#8217;s now convert that into something that is more readable.</p>

<p>Add the following execution on emma4it-maven-plugin:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>74
75
76
77
78
79
80
81
82
83
84
85
86
87
</pre></td><td class="code"><pre class="xml xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>report<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>post-integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>report<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;sourceSets<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;sourceSet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;directory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${project.build.sourceDirectory}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/directory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/sourceSet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/sourceSets<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<p>Now the text, HTML, and XML reports are generated at target/site/emma.</p>

<p><div id="attachment_2481" class="wp-caption alignnone" style="width: 160px"><img src="http://www.sonatype.com/people/wp-content/uploads/2009/06/coveragereport-150x150.png" alt="Emma HTML coverage report" title="coveragereport" width="150" height="150" class="size-thumbnail wp-image-2481" /><p class="wp-caption-text">Emma HTML coverage report</p></div></p>

<p>That is it for part 2.  On the next part, I will show some ideas about testing more complex projects like <a href="http://flexmojos.sonatype.org/">flexmojos</a> and <a href="http://nexus.sonatype.org/">nexus</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=KXgBVUN0VPU:3UuctpBhH_A:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=KXgBVUN0VPU:3UuctpBhH_A:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=KXgBVUN0VPU:3UuctpBhH_A:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=KXgBVUN0VPU:3UuctpBhH_A:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=KXgBVUN0VPU:3UuctpBhH_A:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=KXgBVUN0VPU:3UuctpBhH_A:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/KXgBVUN0VPU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-2-test-coverage-reports/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-2-test-coverage-reports/</feedburner:origLink></item>
		<item>
		<title>Optimal Nexus Repository configuration</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/1DBmvnZwz_w/</link>
		<comments>http://www.sonatype.com/people/2009/06/optimal-nexus-repository-configuration/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 19:00:41 +0000</pubDate>
		<dc:creator>Brian Fox</dc:creator>
		
		<category><![CDATA[How-To]]></category>

		<category><![CDATA[Maven]]></category>

		<category><![CDATA[Nexus]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2486</guid>
		<description><![CDATA[Once you decide to install a Repository Manager, the next decision is how to setup your repositories, particularly if you have multiple teams sharing the same instance. Nexus is very flexible in this area and supports a variety of configurations. I&#8217;ll first describe the options and then discuss the thought process used to decide what [...]]]></description>
			<content:encoded><![CDATA[<p>Once you decide to install a Repository Manager, the next decision is how to setup your repositories, particularly if you have multiple teams sharing the same instance. Nexus is very flexible in this area and supports a variety of configurations. I&#8217;ll first describe the options and then discuss the thought process used to decide what makes sense for your organization.</p>

<h1>Repositories per Project/Team</h1>

<p>The first and most obvious way to support multiple teams is to configure a pair of repositories per team (one release, one snapshot). The team is then given the appropriate C.R.U.D. permissions and they are able to use the system for their artifacts.</p>

<p>Our http://oss.sonatype.org instance is for the most part configured in this manner, where each project like Jetty has their own repositories separate from everyone else.</p>

<h1>Partition Shared Repositories</h1>

<p>Another option is to have a single (or a few) pair of Release/Snapshot repositories for your entire organization. In this case, the access is controlled by a mechanism we call &#8220;Repository Targets.&#8221;</p>

<p>Simply put, a Repository Target is a way to manage a set of artifacts based on their paths. A Repository Target is simply a list of regular expressions and a Name. For example, a Repo Target for Maven would be &#8220;.<em>/org/apache/maven/.</em> and Nexus OSS would be &#8220;.<em>/org/sonatype/nexus/.</em>&#8220;</p>

<p><em>Note: while it is most common to manage artifacts based on the path of their groupId, the Regular Expression is matched against the entire path, and so it is also possible, for example, to define &#8220;Sources&#8221; as &#8220;.*-sources.jar&#8221; &#8230; it&#8217;s also worth noting that Repository Targets are not mutually exclusive. It is perfectly valid for a given path to be contained by multiple targets.</em></p>

<p>In this model, you would create a Repo Target for each project in your system. You are then able to take the Repo Target and associate it with one or more Repositories or Groups in your system. When you do this, new, specific, C.R.U.D. privileges are created. For example, I could take the Maven Repo target, associate it with my Release and Snapshot repository, and now I get privileges I can assign to Create, Read, Update, Delete &#8220;Maven&#8221; (.<em>/org/apache/maven/.</em>) artifacts in my Release and Snapshot repositories.</p>

<p>This method is used to manage the http://repository.apache.org instance, where we have just one Release and Snapshot repository and each project team gets permissions to their artifacts based on the path.</p>

<h1>Which Method is right for me?</h1>

<p>First of all, these choices aren&#8217;t mutually exclusive. In fact, the first option builds upon the default Repository Target of &#8220;.*&#8221; which simply gives you access to all artifacts regardless of the path. You still associate the default Repo Target with specific repositories to create the assignable privileges</p>

<p>In general, it&#8217;s my opinion that fewer repositories will scale better and are easier to manage. It&#8217;s also easier to start off with a single pair of repos, with the default &#8220;All M2&#8243; (.*) target and simply refine the permissions as you scale. Most things that are configured per repository (Cache, Storage location, Snapshot purging, etc) will generally be applicable for all projects, so this mode avoids the duplication of these tasks. Since everything will be stored together in a single folder on disk, it makes backups easier as well.</p>

<p>The reasons why you would want multiple sets of repositories is essentially the opposite of above: If you need different expiration, Snapshot purging or storage folders, then a single shared repo won&#8217;t work. Replication and failover strategies may also make this method easier to support. If you absolutely must maintain total separation between Project teams, ie they can&#8217;t read each other&#8217;s artifacts, then this solution might be more applicable as well. (but is still possible with Repo Targets&#8230;just grant Read to only the appropriate targets)</p>

<p>In Summary, Nexus allows you to control the security of your artifacts based on the repository and/or the path of the artifact, meaning it is possible to slice and dice the system any way you see fit. My default position is to use a few Hosted Repositories as possible and control the permissions by the Repository Target.</p>

<p>It&#8217;s also worth mentioning that the Staging functionality in Pro also uses the Repo Targets to decide how given artifacts are staged, so the definitions are reusable across the system&#8230;and if you are using Staging you will define the</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=1DBmvnZwz_w:UIpvC-n_-Pk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=1DBmvnZwz_w:UIpvC-n_-Pk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=1DBmvnZwz_w:UIpvC-n_-Pk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=1DBmvnZwz_w:UIpvC-n_-Pk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=1DBmvnZwz_w:UIpvC-n_-Pk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=1DBmvnZwz_w:UIpvC-n_-Pk:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/1DBmvnZwz_w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/optimal-nexus-repository-configuration/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/optimal-nexus-repository-configuration/</feedburner:origLink></item>
		<item>
		<title>Publishing Your Artifacts to the Central Maven Repository</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/vsnd8kZO_9Y/</link>
		<comments>http://www.sonatype.com/people/2009/06/publishing-your-artifacts-to-the-central-maven-repository/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 08:00:08 +0000</pubDate>
		<dc:creator>Brian Fox</dc:creator>
		
		<category><![CDATA[Maven]]></category>

		<category><![CDATA[Nexus]]></category>

		<category><![CDATA[central]]></category>

		<category><![CDATA[open source]]></category>

		<category><![CDATA[repository]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2488</guid>
		<description><![CDATA[If your project&#8217;s artifacts are published to the Central Maven repository it is trivial for your users to add a dependency and start using your project&#8217;s library or framework, but if your project is hosted somewhere like Sourceforge and there is no repository manager or repository setup for synchronizing to the Maven Central repository, getting [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.sonatype.com/people/wp-content/uploads/2008/12/nx-big_large1.png" alt="nx-big_large1" title="nx-big_large1" width="100" height="100" class="alignright size-full wp-image-1323" />If your project&#8217;s artifacts are published to the Central Maven repository it is trivial for your users to add a dependency and start using your project&#8217;s library or framework, but if your project is hosted somewhere like Sourceforge and there is no repository manager or repository setup for synchronizing to the Maven Central repository, getting your artifacts into Central can be a pain. The old process for publishing your artifacts to central required several manual steps for you and for the Maven team to setup and enable an rsync location&#8230; assuming you can find a location to host your files at all.</p>

<p>At Sonatype, we want to make synchronizing and publishing your artifacts to central easier both for you and for us, and we want to improve the quality of repository metadata for everyone at the same time. We have setup a dedicated instance of Nexus Professional at <a href="http://oss.sonatype.org">http://oss.sonatype.org</a> specifically to host the artifacts of other Open Source projects.   In this post, I talk about the process of creating a repository for your open source and publishing artifacts that can easily be integrated into the Maven Central repository once they are published to this freely available resource.</p>

<p><span id="more-2488"></span></p>

<p>This instance has actually been running and in production for months by invitation only for projects such as <a href="http://plexus.codehaus.org/">Plexus</a>, <a href="http://jetty.mortbay.org/jetty/index.html">Jetty</a> and <a href="http://ehcache.sourceforge.net">Ehcache</a> (Greg <a href="http://gregluck.com/blog/archives/2009/05/anyone_with_a_p.html">wrote</a>about his experience with migrating to oss.sonatype.org). We now have tooling in place to make it relatively easy for us to process a larger set of requests, so we&#8217;re just now starting to publicize the availability.</p>

<p>To get the process started, go <a href="https://docs.sonatype.com/display/NX/OSS+Repository+Hosting">here</a>. We&#8217;ll setup a release and snapshot repository for your project, along with the appropriate configuration to allow you to use the Staging features for your releases. If you have an existing repository somewhere, we can migrate that for you too.</p>

<p>Since the Sonatype machines sit in the same rack as the Maven Central repository, we are able to synchronize the repositories every hour instead of twice a day.</p>

<p>In the coming weeks we will have a pre-release of Nexus 1.4 Pro running on this instance that allows customizable rules to be run during the staging process. This will allow the system to automatically check things like valid pgp signatures and correct POM parsing. This will ensure that your users have the best experience possible when using your artifacts, and relieve some of the manual validation on your side, a win for everyone.</p>

<p>On the technical details, this instance gets its network connection via <a href="http://www.contegix.com">Contegix</a>&#8217;s high availability network, the same one running Maven Central (and Codehaus.org and Atlassian.com), and the data is backed up offsite daily.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=vsnd8kZO_9Y:rwQswcSOU44:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=vsnd8kZO_9Y:rwQswcSOU44:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=vsnd8kZO_9Y:rwQswcSOU44:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=vsnd8kZO_9Y:rwQswcSOU44:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=vsnd8kZO_9Y:rwQswcSOU44:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=vsnd8kZO_9Y:rwQswcSOU44:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/vsnd8kZO_9Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/publishing-your-artifacts-to-the-central-maven-repository/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/publishing-your-artifacts-to-the-central-maven-repository/</feedburner:origLink></item>
		<item>
		<title>Using Staging Repositories for Deployment in Nexus</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/z4JFtdEIlGY/</link>
		<comments>http://www.sonatype.com/people/2009/06/using-staging-repositories-for-deployment-in-nexus/#comments</comments>
		<pubDate>Wed, 17 Jun 2009 15:44:47 +0000</pubDate>
		<dc:creator>bdemers</dc:creator>
		
		<category><![CDATA[How-To]]></category>

		<category><![CDATA[Nexus]]></category>

		<category><![CDATA[nexus pro]]></category>

		<category><![CDATA[staging]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2456</guid>
		<description><![CDATA[For a number of reasons you might want to require your developers to use a staging repository.    Staged software releases in Nexus Professional are the best way to enable your development team to push a release to an artifact repository such as Nexus while providing management and quality assurance with a way to test and [...]]]></description>
			<content:encoded><![CDATA[<p>For a number of reasons you might want to require your developers to use a staging repository.    Staged software releases in <a href="http://www.sonatype.com/products/nexus">Nexus Professional</a> are the best way to enable your development team to push a release to an artifact repository such as Nexus while providing management and quality assurance with a way to test and approve a release before &#8220;burning&#8221; it to production.  If you want to learn how to make a staged release, you can watch this <a href="http://www.sonatype.com/people/2009/01/nexus-professional-what-is-staging/">video</a>. or read the remainder of this blog post.
<span id="more-2456"></span>
First step, is to download Nexus Professional if you don&#8217;t already have it installed, you can do so, by going to the Nexus Professional product page and <a href="http://www.sonatype.com/products/nexus">clicking on the download link</a> in the right-hand menu.   Once you&#8217;ve downloaded Nexus, log in as an administrator as you must have administrative rights to perform the following configuration:</p>

<ol>
    <li>From Nexus, click on the &#8216;Repositories&#8217; link in left navigation.</li>
    <li>Click on the repository you want to use, or create one (If you need help with that take a look at the Nexus book, <a href="http://www.sonatype.com/books/nexus-book/reference/procure-sect-configure.html#procue-sect-create-hosted">here</a>)</li>
    <li>Click on the &#8216;Configuration&#8217; tab.</li>
    <li>Set the &#8216;Allow Deployment&#8217; field to false.</li>
    <li>Click the Save button.</li>
</ol>

<p><img class="alignnone size-large wp-image-2460" title="edit repository screen shot" src="http://www.sonatype.com/people/wp-content/uploads/2009/06/force-staging-repo2-1024x577.png" alt="edit repository screen shot" width="580" /></p>

<p>That is it! Users will not be able to deploy or upload artifacts directly to the repository.  All artifacts must be staged and promoted to this repository.  For more information on staging and promoting take a look at <a href="http://www.sonatype.com/books/nexus-book/reference/staging-sect-managing-staging.html">this</a>,  or with the maven plugin, <a href="http://www.sonatype.com/books/nexus-book/reference/ch09s07.html">here</a>.</p>

<p><strong>Create a Staging repository</strong></p>

<p>To create a staging repository:</p>

<ol>
    <li>From Nexus, click on the &#8216;Staging&#8217; link in left navigation.</li>
    <li>Click the &#8216;Add&#8217; button then the &#8216;Staging Profile&#8217; item.</li>
    <li>Enter the following information:
<ul>
    <li>Profile Name: Staging Demo Profile</li>
    <li>Profile Repository Target: All (Maven2)</li>
    <li>Staging Repository ID Template: staging-demo</li>
    <li>Staging Repository Name Template: Staging Demo</li>
    <li>Staging Repository Template: Default Release Hosted Repository Template</li>
    <li>Target Groups: Public Releases</li>
</ul>
</li>
    <li>Click the &#8216;Save&#8217; button</li>
</ol>

<p><img class="alignnone size-large wp-image-2472" title="create staging repo" src="http://www.sonatype.com/people/wp-content/uploads/2009/06/staging-howto-1024x480.png" alt="create staging repo" width="580"  /></p>

<p><strong>Assign permissions to users</strong></p>

<p>A new role is created for each staging profile that is created ( in this example the role is &#8216;Staging Deployer: (Staging Demo Profile)&#8217;).  Assign the new role to your users.  You can find more details on user management, <a href="http://www.sonatype.com/books/nexus-book/reference/config.html#config-sect-managing-users">here</a>.</p>

<p><img class="alignnone size-large wp-image-2471" title="assign staging role" src="http://www.sonatype.com/people/wp-content/uploads/2009/06/create-user-1024x464.png" alt="assign staging role" width="580"  /></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=z4JFtdEIlGY:N96j3JN75Gw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=z4JFtdEIlGY:N96j3JN75Gw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=z4JFtdEIlGY:N96j3JN75Gw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=z4JFtdEIlGY:N96j3JN75Gw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=z4JFtdEIlGY:N96j3JN75Gw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=z4JFtdEIlGY:N96j3JN75Gw:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/z4JFtdEIlGY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/using-staging-repositories-for-deployment-in-nexus/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/using-staging-repositories-for-deployment-in-nexus/</feedburner:origLink></item>
		<item>
		<title>Nexus Open Source and Hudson on EC2</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/SvDg7iltSbg/</link>
		<comments>http://www.sonatype.com/people/2009/06/nexus-open-source-and-hudson-on-ec2/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 19:11:49 +0000</pubDate>
		<dc:creator>tim</dc:creator>
		
		<category><![CDATA[Nexus]]></category>

		<category><![CDATA[cloud]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2447</guid>
		<description><![CDATA[If you are interested in running Nexus and Hudson on Amazon&#8217;s Elastic Computing (EC2) service, there is now a public image that contains Maven, Nexus, Hudson, and the OpenJDK.    If you use Amazon&#8217;s easy-to-use AWS Console, running a state-of-the-art build service with Nexus and Hudson is one click away.    [...]]]></description>
			<content:encoded><![CDATA[<p>If you are interested in running Nexus and Hudson on Amazon&#8217;s Elastic Computing (EC2) service, there is now a public image that contains Maven, Nexus, Hudson, and the OpenJDK.    If you use Amazon&#8217;s easy-to-use <a href="http://console.aws.amazon.com">AWS Console</a>, running a state-of-the-art build service with Nexus and Hudson is one click away.    Here are the details for those of you interested in running Nexus and Hudson on the cloud:</p>

<ul>
  <li><b>Manifest:</b> <a href="http://s3.amazonaws.com/sonatype-images/nexus-os-1.3.4_hudson-20090608.manifest.xml">sonatype-images/nexus-os-1.3.4_hudson-20090608.manifest.xml</a></li>
  <li><b>AMI ID:</b> ami-7314f21a</li>
  <li><b>Operating System:</b> Fedora Core 8</li>
  <li><b>Platform:</b> i386</li>
</ul>

<p>Launch it.  In minutes, you will have a capable build server.   Read more to find out about some suggested next steps to secure your new build server.</p>

<p><span id="more-2447"></span></p>

<p><b>What&#8217;s Installed?</b>  This instance is simply the latest installation of <a href="https://hudson.dev.java.net/">Hudson 1.309</a>, <a href="http://nexus.sonatype.org">Nexus 1.3.4 Open Source</a>, <a href="http://openjdk.java.net/install/#fedora">OpenJDK 1.6.0</a>, and <a href="http://maven.apache.org">Maven 2.1.0</a>.      Nexus is installed in /usr/local/nexus and Hudson is installed on Tomcat 6.0.20 in /usr/local/hudson.    Both Nexus and Hudson are configured to startup in /etc/init.d/nexus and /etc/init.d/hudson. </p>

<p><b>Post Launch Instructions:</b>  Since Nexus and Hudson are both running with the default authentication configuration, it is imperative that you <b>change the default administrative password of Nexus after installation (the default is &#8220;admin123&#8243;)</b>.    To change the Nexus password:</p>

<ol>
  <li>Go to http://&lt;host&gt;/nexus</li>
  <li>Log in as &#8220;admin&#8221; using the default password &#8220;admin123&#8243;</li>
  <li>Click on &#8220;Change Password&#8221; in the Security Menu</li>
</ol>

<p>Also, it is imperative that you turn on security for your Hudson instance.  To do this:</p>

<ol>
  <li>Go to http://&lt;host&gt;/hudson</li>
  <li>Click on &#8220;Manage Hudson&#8221;</li>
  <li>Click on &#8220;Configure System&#8221;</li>
  <li>Make sure that &#8220;Enable Security&#8221; is checked, and configure Hudson security.    If you don&#8217;t have an LDAP server, just use Hudson&#8217;s on Security Database</li>
</ol>

<p>While you are at it, you will need to configure Hudson&#8217;s JDK and Maven installation.   To do this:</p>

<ol>
  <li>Go to http://&lt;host&gt;/hudson</li>
  <li>Click on &#8220;Manage Hudson&#8221;</li>
  <li>Click on &#8220;Configure System&#8221;</li>
  <li>Click on ADD JDK.  At this point, you can download a JDK directly from Sun, or you can point your Hudson instance at the OpenJDK 1.6.0 installed on this EC2 instance.   The JAVA_HOME directory for OpenJDK on this box is: /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/</li>
  <li>Click on Add Maven to add a Maven installation.   At this point, you can install Maven directly from Apache, or you can point Hudson at the Maven 2.1.0 instance installed on this machine.   M2_HOME on this machine is /usr/local/maven.</li>
</ol>

<h3>Long-lived Build Machines on EC2 (Get an EBS Volume)</h3>

<p>If you are planning on running this instance as a long-running build server, you will likely want to configure the sonatype-work directory to run on an EBS volume.     If you do end up running Hudson and Nexus on this instance for a long time, and you are planning on depending on it: invest in an EBS volume and move /usr/local/nexus and /usr/local/hudson to run on that persistent volume.    This way, you&#8217;ll have the peace of mind that your build and repository data will persistent in the event of unforeseen downtime.</p>

<p>Happy Nexusing</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=SvDg7iltSbg:j04Ytp1kvuw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=SvDg7iltSbg:j04Ytp1kvuw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=SvDg7iltSbg:j04Ytp1kvuw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=SvDg7iltSbg:j04Ytp1kvuw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=SvDg7iltSbg:j04Ytp1kvuw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=SvDg7iltSbg:j04Ytp1kvuw:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/SvDg7iltSbg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/nexus-open-source-and-hudson-on-ec2/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/nexus-open-source-and-hudson-on-ec2/</feedburner:origLink></item>
		<item>
		<title>Nexus Indexer API: Part 2</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/DWGtEM1gF4A/</link>
		<comments>http://www.sonatype.com/people/2009/06/nexus-indexer-api-part-2/#comments</comments>
		<pubDate>Sun, 07 Jun 2009 16:16:23 +0000</pubDate>
		<dc:creator>damian</dc:creator>
		
		<category><![CDATA[Nexus]]></category>

		<category><![CDATA[Sonatype]]></category>

		<category><![CDATA[indexer]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2423</guid>
		<description><![CDATA[This series of Nexus Indexer posts will focus on integrating the Nexus Indexer into your own application.    If you have an application that needs to search for an artifact by GAV coordinates, or by class name, you can use the Nexus Index format and the Nexus Indexer API to very easily search [...]]]></description>
			<content:encoded><![CDATA[<p>This series of Nexus Indexer posts will focus on integrating the Nexus Indexer into your own application.    If you have an application that needs to search for an artifact by GAV coordinates, or by class name, you can use the Nexus Index format and the Nexus Indexer API to very easily search and locate artifacts in any repository that creates a Nexus Index.  There are four main functions that are exposed in the Nexus Indexer API.</p>

<ul>
    <li><a href="http://www.sonatype.com/people/2009/06/nexus-indexer-api-part-1/">Indexing (Part 1)</a></li>
    <li>Searching</li>
    <li>Packing</li>
    <li>Updating</li>
</ul>

<p>This post will focus on Searching and provide you with some concrete code examples that show you how to use the indexer search capabilities in your application.
<span id="more-2423"></span></p>

<h1>Searching</h1>

<p>The Nexus Indexer uses Apache Lucene to handle storage and searching of the index data, and provides a very simple method to search against fields in the index.  Below I have extended my plexus component from the Part 1 of this blog series, to include search functionality.</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.damian</span>;
...
<span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * Sample app to show how to integrate with the nexus indexer.  Note that this is a simple plexus
 * component extending the SampleApp interface
 * 
 * public interface SampleApp
 * {
 *    void index() 
 *        throws IOException;
 *    
 *    Set&lt;ArtifactInfo&gt; searchIndexFlat( String field, String value ) 
 *        throws IOException;
 *    
 *    Set&lt;ArtifactInfo&gt; searchIndexFlat( Query query )
 *        throws IOException;
 *    
 *    Map&lt;String, ArtifactInfoGroup&gt; searchIndexGrouped( String field, String value )
 *        throws IOException;
 *    
 *    Map&lt;String, ArtifactInfoGroup&gt; searchIndexGrouped( String field, String value, Grouping grouping )
 *        throws IOException;
 *    
 *    Map&lt;String, ArtifactInfoGroup&gt; searchIndexGrouped( Query q, Grouping grouping )
 *        throws IOException;
 * }
 * 
 * @author Damian
 *
 */</span>
@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role <span style="color: #339933;">=</span> SampleApp.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DefaultSampleApp
    <span style="color: #000000; font-weight: bold;">implements</span> SampleApp,
        Initializable,
        Disposable
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// The nexus indexer</span>
    @Requirement
    <span style="color: #000000; font-weight: bold;">private</span> NexusIndexer indexer;
&nbsp;
    ...
&nbsp;
    <span style="color: #666666; font-style: italic;">// search for artifacts</span>
    <span style="color: #000000; font-weight: bold;">public</span> Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> searchIndexFlat<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span> field, <span style="color: #003399;">String</span> value <span style="color: #009900;">&#41;</span> 
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Build a query that will search the documents for the field set to the supplied value</span>
        <span style="color: #666666; font-style: italic;">// This uses predefined logic to define the query</span>
        <span style="color: #666666; font-style: italic;">// See http://svn.sonatype.org/nexus/trunk/nexus-indexer/src/main/java/org/sonatype/nexus/index/DefaultQueryCreator.java</span>
        <span style="color: #666666; font-style: italic;">// for details</span>
        Query query <span style="color: #339933;">=</span> indexer.<span style="color: #006633;">constructQuery</span><span style="color: #009900;">&#40;</span> field, value <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> searchIndexFlat<span style="color: #009900;">&#40;</span> query <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// search for artifacts using pre-built query</span>
    <span style="color: #000000; font-weight: bold;">public</span> Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> searchIndexFlat<span style="color: #009900;">&#40;</span> Query query <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Build the request</span>
        FlatSearchRequest request <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FlatSearchRequest<span style="color: #009900;">&#40;</span> query <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// Perform the search</span>
        FlatSearchResponse response <span style="color: #339933;">=</span> indexer.<span style="color: #006633;">searchFlat</span><span style="color: #009900;">&#40;</span> request <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// Return the artifact info objects</span>
        <span style="color: #000000; font-weight: bold;">return</span> response.<span style="color: #006633;">getResults</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Map<span style="color: #339933;">&lt;</span>String, ArtifactInfoGroup<span style="color: #339933;">&gt;</span> searchIndexGrouped<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span> field, <span style="color: #003399;">String</span> value <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// We will simply use the GAV grouping, meaning that each groupId/artifactId/version/classifier</span>
        <span style="color: #666666; font-style: italic;">// will have its own entry in the returned map        </span>
        <span style="color: #000000; font-weight: bold;">return</span> searchIndexGrouped<span style="color: #009900;">&#40;</span> field, value, <span style="color: #000000; font-weight: bold;">new</span> GAVGrouping<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Map<span style="color: #339933;">&lt;</span>String, ArtifactInfoGroup<span style="color: #339933;">&gt;</span> searchIndexGrouped<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span> field, <span style="color: #003399;">String</span> value, Grouping grouping <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Build a query that will search the documents for the field set to the supplied value</span>
        <span style="color: #666666; font-style: italic;">// This uses predefined logic to define the query</span>
        <span style="color: #666666; font-style: italic;">// See http://svn.sonatype.org/nexus/trunk/nexus-indexer/src/main/java/org/sonatype/nexus/index/DefaultQueryCreator.java</span>
        <span style="color: #666666; font-style: italic;">// for details</span>
        Query query <span style="color: #339933;">=</span> indexer.<span style="color: #006633;">constructQuery</span><span style="color: #009900;">&#40;</span> field, value <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> searchIndexGrouped<span style="color: #009900;">&#40;</span> query, grouping <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Map<span style="color: #339933;">&lt;</span>String, ArtifactInfoGroup<span style="color: #339933;">&gt;</span> searchIndexGrouped<span style="color: #009900;">&#40;</span> Query q, Grouping grouping <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
    <span style="color: #009900;">&#123;</span>
        GroupedSearchRequest request <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GroupedSearchRequest<span style="color: #009900;">&#40;</span> q, grouping <span style="color: #009900;">&#41;</span>;
&nbsp;
        GroupedSearchResponse response <span style="color: #339933;">=</span> indexer.<span style="color: #006633;">searchGrouped</span><span style="color: #009900;">&#40;</span> request <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> response.<span style="color: #006633;">getResults</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>As you can see, there are 2 ways to handle how the search is performed.  The first is to use the nexus indexer to decide what type of lucene Query to create, based upon the input string.  The second is to pass in your own lucene Query object, you can use any object that extends the org.apache.lucene.search.Query abstract class.  If you choose to let the nexus indexer build your query, the following rules will apply to the search term:</p>

<ul>
    <li>string converted to lowercase</li>
    <li>if first character is &#8216;^&#8217; drop it</li>
    <li>if first character anything other than &#8216;^&#8217; prepend string with &#8216;*&#8217;</li>
    <li>if last character is &#8216; &#8216;, &#8216;<' or '$' drop it</li>
        <li>if last character anything other than &#8216; &#8216;, &#8216;<' or '$' append '*' to end of string</li>
        <li>if modified string does not contain &#8216;*&#8217; then a TermQuery is used (exact match)</li>
        <li>if modified string contains &#8216;*&#8217; in last position, then a PrefixQuery is used (and &#8216;*&#8217; is dropped from string)</li>
        <li>if modified string contains &#8216;*&#8217; in any other position, then a WildcardQuery is used</li>
</ul>

<p>There will probably be occassions where this list of rules doesn&#8217;t apply to your use case, so you instead will want to give the Indexer your own Query object, that leaves you to choose from the many Query objects that lucene provides, or even to make your own if necessary.</p>

<p>You will also notice that there are 2 different types of result sets you can get back, flat or grouped.  Flat results are simply a Set of ArtifactInfo objects for each match in the index.  Grouped results will combine results based upon the Grouping you request (in my sample, the default is GAVGrouping which will group items together that share the same groupId/artifactId/version/classifier).</p>

<p>Here are some samples from a unit test in the project source code, that do the different kinds of searching.</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;value&quot;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearchWithTermQuery<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// This type of query will be totally built outside of nexus indexer, and will not</span>
        <span style="color: #666666; font-style: italic;">// be tied to constraints defined in </span>
        <span style="color: #666666; font-style: italic;">// http://svn.sonatype.org/nexus/trunk/nexus-indexer/src/main/java/org/sonatype/nexus/index/DefaultQueryCreator.java</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// A TermQuery matches equal strings</span>
        Query q <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> TermQuery<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> Term<span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;value&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> q <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearchWithPrefixQuery<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// This type of query will be totally built outside of nexus indexer, and will not</span>
        <span style="color: #666666; font-style: italic;">// be tied to constraints defined in </span>
        <span style="color: #666666; font-style: italic;">// http://svn.sonatype.org/nexus/trunk/nexus-indexer/src/main/java/org/sonatype/nexus/index/DefaultQueryCreator.java</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// A PrefixQuery will look for any documents containing the MY_FIELD term that starts with val</span>
        Query q <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PrefixQuery<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> Term<span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;val&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> q <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearchWithWildcardQuery<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// This type of query will be totally built outside of nexus indexer, and will not</span>
        <span style="color: #666666; font-style: italic;">// be tied to constraints defined in </span>
        <span style="color: #666666; font-style: italic;">// http://svn.sonatype.org/nexus/trunk/nexus-indexer/src/main/java/org/sonatype/nexus/index/DefaultQueryCreator.java</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// A WildcardQuery supports the * and ? wildcard characters</span>
        Query q <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> WildcardQuery<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> Term<span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;*alue&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        Set<span style="color: #339933;">&lt;</span>ArtifactInfo<span style="color: #339933;">&gt;</span> artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> q <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// A WildcardQuery supports the * and ? wildcard characters</span>
        q <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> WildcardQuery<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> Term<span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;v?lue&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> q <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// A WildcardQuery supports the * and ? wildcard characters</span>
        q <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> WildcardQuery<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> Term<span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;val*&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        artifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexFlat</span><span style="color: #009900;">&#40;</span> q <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is null&quot;</span>, artifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifacts is empty&quot;</span>, artifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfo ai <span style="color: #339933;">:</span> artifacts <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned artifact has invalid data&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, ai.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;    
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearchGroup<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        Map<span style="color: #339933;">&lt;</span>String,ArtifactInfoGroup<span style="color: #339933;">&gt;</span> groupedArtifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexGrouped</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>, <span style="color: #0000ff;">&quot;value&quot;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned groupedArtifacts is null&quot;</span>, groupedArtifacts <span style="color: #009900;">&#41;</span>;
        assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned groupedArtifacts should not be empty&quot;</span>, groupedArtifacts.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span> ArtifactInfoGroup artifactGroup <span style="color: #339933;">:</span> groupedArtifacts.<span style="color: #006633;">values</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> parts <span style="color: #339933;">=</span> artifactGroup.<span style="color: #006633;">getGroupKey</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;:&quot;</span> <span style="color: #009900;">&#41;</span>;
            <span style="color: #666666; font-style: italic;">//1st part groupId</span>
            <span style="color: #666666; font-style: italic;">//2nd part artifactId</span>
            <span style="color: #666666; font-style: italic;">//3rd part version</span>
            <span style="color: #666666; font-style: italic;">//4th part classifier</span>
            assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;should be 4 parts to the group key&quot;</span>, <span style="color: #cc66cc;">4</span>, parts.<span style="color: #006633;">length</span> <span style="color: #009900;">&#41;</span>;
            assertFalse<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;each group should contain at least 1 artifact&quot;</span>, artifactGroup.<span style="color: #006633;">getArtifactInfos</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testSampleSearchGroupNewGrouping<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        app.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #666666; font-style: italic;">// Search using my own grouping, which will group based upon the MY_FIELD parameter</span>
        Map<span style="color: #339933;">&lt;</span>String, ArtifactInfoGroup<span style="color: #339933;">&gt;</span> groupedArtifacts <span style="color: #339933;">=</span> app.<span style="color: #006633;">searchIndexGrouped</span><span style="color: #009900;">&#40;</span>
            SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span>,
            <span style="color: #0000ff;">&quot;value&quot;</span>,
            <span style="color: #000000; font-weight: bold;">new</span> AbstractGrouping<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                @Override
                <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">String</span> getGroupKey<span style="color: #009900;">&#40;</span> ArtifactInfo artifactInfo <span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000000; font-weight: bold;">return</span> artifactInfo.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> SampleIndexCreator.<span style="color: #006633;">MY_FIELD</span> <span style="color: #009900;">&#41;</span>;
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        assertNotNull<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned groupedArtifacts is null&quot;</span>, groupedArtifacts <span style="color: #009900;">&#41;</span>;
        assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;returned groupedArtifacts should have 1 entry&quot;</span>, <span style="color: #cc66cc;">1</span>, groupedArtifacts.<span style="color: #006633;">size</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
        assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;group key should be value&quot;</span>, <span style="color: #0000ff;">&quot;value&quot;</span>, groupedArtifacts.<span style="color: #006633;">values</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">iterator</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">next</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getGroupKey</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>As you can see from the last test method, you can create your own Grouping object, to group things anyway you see fit, in this case, the results will be grouped using the MY_FIELD parameter.</p>

<p>That&#8217;s all for now, next time we will get into packing up indexes for publishing.</p>

<p>Sample Maven project can be found here <a href="http://svn.sonatype.org/nexus/trunk/sandbox/nexus-indexer-sample">http://svn.sonatype.org/nexus/trunk/sandbox/nexus-indexer-sample</a> and will be updated periodically as I put together more details for the blog posts.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=DWGtEM1gF4A:NhiggiavvnE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=DWGtEM1gF4A:NhiggiavvnE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=DWGtEM1gF4A:NhiggiavvnE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=DWGtEM1gF4A:NhiggiavvnE:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=DWGtEM1gF4A:NhiggiavvnE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=DWGtEM1gF4A:NhiggiavvnE:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/DWGtEM1gF4A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/nexus-indexer-api-part-2/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/nexus-indexer-api-part-2/</feedburner:origLink></item>
		<item>
		<title>m2eclipse Book Now on Scribd</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/nLRjgXO-UGk/</link>
		<comments>http://www.sonatype.com/people/2009/06/m2eclipse-book-now-on-scribd/#comments</comments>
		<pubDate>Sun, 07 Jun 2009 16:12:48 +0000</pubDate>
		<dc:creator>tim</dc:creator>
		
		<category><![CDATA[Book]]></category>

		<category><![CDATA[m2eclipse]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2441</guid>
		<description><![CDATA[The m2eclipse book is now available on Scribd.

                                                [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.scribd.com/doc/16196659/Developing-with-Eclipse-and-Maven">m2eclipse book is now available on Scribd</a>.</p>

<p><object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_329113431528321" name="doc_329113431528321" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle"  height="500" width="580" >      <param name="movie" value="http://d.scribd.com/ScribdViewer.swf?document_id=16196659&#038;access_key=key-nyccxuh84ac8y58y9y9&#038;page=1&#038;version=1&#038;viewMode=book">        <param name="quality" value="high">         <param name="play" value="true">        <param name="loop" value="true">        <param name="scale" value="showall">        <param name="wmode" value="opaque">         <param name="devicefont" value="false">     <param name="bgcolor" value="#ffffff">      <param name="menu" value="true">        <param name="allowFullScreen" value="true">         <param name="allowScriptAccess" value="always">         <param name="salign" value="">                      <param name="mode" value="book">                <embed src="http://d.scribd.com/ScribdViewer.swf?document_id=16196659&#038;access_key=key-nyccxuh84ac8y58y9y9&#038;page=1&#038;version=1&#038;viewMode=book" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_329113431528321_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle" mode="book" height="500" width="580"></embed>           </object></p>

<div style="margin: 6px auto 3px auto; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 12px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; display: block;">    <a href="http://www.scribd.com/upload" style="text-decoration: underline;">Publish at Scribd</a> or <a href="http://www.scribd.com/browse" style="text-decoration: underline;">explore</a> others:            <a href="http://www.scribd.com/explore/HowtoGuides-Manuals/" style="text-decoration: underline;">How-to-Guides &#038; Manu</a>                  <a href="http://www.scribd.com/tag/development" style="text-decoration: underline;">development</a>              <a href="http://www.scribd.com/tag/java" style="text-decoration: underline;">java</a>       </div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=nLRjgXO-UGk:PVXz-ZQLy14:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=nLRjgXO-UGk:PVXz-ZQLy14:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=nLRjgXO-UGk:PVXz-ZQLy14:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=nLRjgXO-UGk:PVXz-ZQLy14:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=nLRjgXO-UGk:PVXz-ZQLy14:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=nLRjgXO-UGk:PVXz-ZQLy14:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/nLRjgXO-UGk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/m2eclipse-book-now-on-scribd/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/m2eclipse-book-now-on-scribd/</feedburner:origLink></item>
		<item>
		<title>Integration tests with Maven (Part 1): Failsafe Plugin</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/mEXGjmHGjaE/</link>
		<comments>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-1-failsafe-plugin/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 17:40:08 +0000</pubDate>
		<dc:creator>velo</dc:creator>
		
		<category><![CDATA[Maven]]></category>

		<category><![CDATA[failsafe]]></category>

		<category><![CDATA[junit]]></category>

		<category><![CDATA[quality]]></category>

		<category><![CDATA[surefire]]></category>

		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2408</guid>
		<description><![CDATA[Everyone knows Maven is great for running unit tests, and it is usually one of the first things that people learn when they are adopting Maven as a technology.   Integration tests are another matter, and require a more detailed introduction.  In this series of articles, I will explain how to set up [...]]]></description>
			<content:encoded><![CDATA[<p>Everyone knows Maven is great for running unit tests, and it is usually one of the first things that people learn when they are adopting Maven as a technology.   Integration tests are another matter, and require a more detailed introduction.  In this series of articles, I will explain how to set up integration tests in Maven starting the series by testing a simple jar and then advancing into more complex scenarios.</p>

<p><span id="more-2408"></span></p>

<h3>The application</h3>

<p>Let&#8217;s define a very simple application to be tested.  The application will return an exit code equal to the number of command-line parameters.  Running the program with no parameters will produce an exit code equal to zero, two parameters exit code two, and so on.</p>

<p>The application:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sonatype.simpleclientapp</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Main
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">exit</span><span style="color: #009900;">&#40;</span> execute<span style="color: #009900;">&#40;</span> args <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">int</span> execute<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> args <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> 0;
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> args.<span style="color: #006633;">length</span>;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>This class is very simple to test, in the next section you will see how you can write a simple integration test using JUnit.</p>

<h3>Creating and running integration tests</h3>

<p>Let&#8217;s create a simple integration test using JUnit:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sonatype.simpleclientapp</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.File</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">junit.framework.TestCase</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MainIT
    <span style="color: #000000; font-weight: bold;">extends</span> TestCase
<span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testExecute<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        assertEquals<span style="color: #009900;">&#40;</span> 0, execute<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
        assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">1</span>, execute<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#123;</span> <span style="color: #0000ff;">&quot;one&quot;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
        assertEquals<span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">6</span>, execute<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#123;</span> <span style="color: #0000ff;">&quot;one&quot;</span>, <span style="color: #0000ff;">&quot;two&quot;</span>, <span style="color: #0000ff;">&quot;three&quot;</span>, <span style="color: #0000ff;">&quot;four&quot;</span>, <span style="color: #0000ff;">&quot;five&quot;</span>, <span style="color: #0000ff;">&quot;six&quot;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> execute<span style="color: #009900;">&#40;</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">File</span> jar <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;target/simple-client-app-1.0-SNAPSHOT.jar&quot;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
        <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> execArgs <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span>args.<span style="color: #006633;">length</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#93;</span>;
        <span style="color: #003399;">System</span>.<span style="color: #006633;">arraycopy</span><span style="color: #009900;">&#40;</span> args, 0, execArgs, <span style="color: #cc66cc;">3</span>, args.<span style="color: #006633;">length</span> <span style="color: #009900;">&#41;</span>;
        execArgs<span style="color: #009900;">&#91;</span>0<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;java&quot;</span>;
        execArgs<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;-jar&quot;</span>;
        execArgs<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> jar.<span style="color: #006633;">getCanonicalPath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #003399;">Process</span> p <span style="color: #339933;">=</span> <span style="color: #003399;">Runtime</span>.<span style="color: #006633;">getRuntime</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">exec</span><span style="color: #009900;">&#40;</span> execArgs <span style="color: #009900;">&#41;</span>;
        p.<span style="color: #006633;">waitFor</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #000000; font-weight: bold;">return</span> p.<span style="color: #006633;">exitValue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>Note that this test needs the packaged jar (simple-client-app-1.0-SNAPSHOT.jar), which isn&#8217;t created when surefire runs the unit tests.</p>

<p>To run this we need a different approach. By different approach I mean a different plugin: the <a href="http://mojo.codehaus.org/failsafe-maven-plugin/">Failsafe Maven Plugin</a>.  The Failsafe Plugin is a fork of the Surefire plugin designed to run integration tests.</p>

<p>The Failsafe plugin goals are designed to run after the package phase, on the integration-test phase.</p>

<p>The Maven lifecycle has four phases for running integration tests:</p>

<ul>
<li>pre-integration-test: on this phase we can start any required service or do any action, like starting a database, or starting a webserver, anything&#8230; you can think on this as Junit.setUp()</li>
<li>integration-test: failsafe will run the test on this phase, so after all required services are started.</li>
<li>post-integration-test: time to shutdown all services&#8230; you can think of this as Junit.tearDown()</li>
<li>verify: failsafe runs another goal that interprets the results of tests here, if any tests didn&#8217;t pass failsafe will display the results and exit the build.</li>
</ul>

<p>Configuring Failsafe in the POM:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="xml xml" style="font-family:monospace;">      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.codehaus.mojo<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>failsafe-maven-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>2.4.3-alpha-1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
              <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
              <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>verify<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<p>By default, the Surefire plugin executes **/Test&#42;.java, **/&#42;Test.java, and **/&#42;TestCase.java test classes.    The Failsafe plugin will look for **/IT&#42;.java, **/&#42;IT.java, and **/&#42;ITCase.java.  If you are using both the Surefire and Failsafe plugins, make sure that you use this naming convention to make it easier to identify which tests are being executed by which plugin.</p>

<p>In the next part of this series, I will talk about test coverage and demonstrate a method of including coverage of both Unit Tests and Integration Tests in a report that can be generated for a Maven project.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=mEXGjmHGjaE:iq7ZI65kaVk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=mEXGjmHGjaE:iq7ZI65kaVk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=mEXGjmHGjaE:iq7ZI65kaVk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=mEXGjmHGjaE:iq7ZI65kaVk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=mEXGjmHGjaE:iq7ZI65kaVk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=mEXGjmHGjaE:iq7ZI65kaVk:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/mEXGjmHGjaE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-1-failsafe-plugin/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/integration-tests-with-maven-part-1-failsafe-plugin/</feedburner:origLink></item>
		<item>
		<title>Writing Plugins for Nexus (Part 1)</title>
		<link>http://feedproxy.google.com/~r/sonatype/~3/seSSNwPMwwY/</link>
		<comments>http://www.sonatype.com/people/2009/06/writing-plugins-for-nexus-part-1/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 12:00:44 +0000</pubDate>
		<dc:creator>Tamas</dc:creator>
		
		<category><![CDATA[Nexus]]></category>

		<category><![CDATA[plugins]]></category>

		<guid isPermaLink="false">http://www.sonatype.com/people/?p=2336</guid>
		<description><![CDATA[Nexus is a Plexus application, it uses Plexus as a container.    As we are well aware, Plexus isn&#8217;t the only Depedency Injection framework currently available.   We decided to design the Nexus plugin mechanism to allow for extensibility in a container independent way.   If you want to write a [...]]]></description>
			<content:encoded><![CDATA[<p>Nexus is a Plexus application, it uses Plexus as a container.    As we are well aware, Plexus isn&#8217;t the only Depedency Injection framework currently available.   We decided to design the Nexus plugin mechanism to allow for extensibility in a container independent way.   If you want to write a plugin for Nexus (and possibly all other Sonatype products) you don&#8217;t need to pick up a book on Plexus, we&#8217;re trying to make it easier for someone to innovate on the Nexus platform without having to adopt a whole series of technologies.</p>

<p>This post covers some of the initial steps, that are required to write a plugin for Nexus.  Although Nexus is a Plexus application, we want to give 3rd party developers ability to extend Nexus, without forcing them to know Plexus.   We also want to give 3rd party developers the ability to extend Nexus, without burying themselves into Nexus internals.   Clearly if someone wants to add complex, highly custom behavior to Nexus they will need to dive into the internals, but it should be easy to add a simple extension to Nexus without having a PhD in Nexus Internals.    We are also committed to adopting 3rd party &#8220;specs/suggestions/APIs&#8221; that look promising, even if it comes from another IoC provider.</p>

<p>Now, let&#8217;s replace the &#8220;Nexus&#8221; in above sentences with &#8220;Sonatype Application&#8221; in the sentences above. It&#8217;s not so different, right?  At Sonatype, we&#8217;re convinced that providing an intuitive plugin and extension mechanism is critical for adoption and we want to make it as straightforward as possible.  To start this discussion, we need first a look at how Plexus works.</p>

<p><span id="more-2336"></span></p>

<h3>Plexus in 3 minutes</h3>

<p>Plexus &#8220;managed beans&#8221; are called &#8220;components&#8221;.  In contrast to the way most people use Spring, where each bean has a unique name or &#8220;ID&#8221;, Plexus components are addressed with <strong>two</strong> coordinates: <em>role</em> and <em>hint</em>.</p>

<p>Plexus encourages the use of interfaces when defining components. Generally spoken, when implementing one component in Plexus, you will almost always end up with two compilation units: a Java interface, that sets the contract that your component fulfills, and an implementation (or multiple implementations) that implements the contract interface. Again, this is not enforced at all, but is considered as &#8220;best practice&#8221;.</p>

<p>While these two coordinates are internally represented as plain strings, the role is usually a FQN of the interface that component &#8220;provides&#8221; (or implements).   For example, the role might be something like &#8220;com.sonatype.component.TestComponent&#8221; which is the FQN of an interface used to define the contract of the component.   This is not enforced at all in Plexus and it&#8217;s tooling (for example, the plexus-component-metadata Maven plugin), but again, is considered a &#8220;best practice&#8221;. The &#8220;hint&#8221; is actually a free string qualifier, to be able to differentiate amongst multiple implementors (components) with same role, if needed. There is one special hint used internally by Plexus: &#8220;default&#8221;, which is used when no hint is supplied.</p>

<p>Why is this important? Well, usually you have two major situations with your components (managed beans). For one component contract interface you either have:</p>

<ul>
<li>one &#8220;default&#8221; implementation across your application (singular case),</li>
<li>or you may have multiple different implementations of same component contract (plural case)</li>
</ul>

<p>Do not confuse the singular case with &#8220;singleton&#8221; pattern: in both cases the components (managed beans) <strong>are singletons</strong>. We are just providing <strong>one or multiple implementations</strong> for same interface. But in both cases, the actual classes being created by container are singletons (unless you say different in your Plexus annotations, but that&#8217;s another story, and I don&#8217;t want to complicate existing examples).</p>

<p>Another case is how the &#8220;consumer&#8221; of that component &#8212; which is probably some other component in your application &#8212; decides which implementation it wants to use. Or maybe it doesn&#8217;t care at all?</p>

<p>The simplest example of &#8220;singular&#8221; case, the component contract interface and it&#8217;s implementation:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> MyComponent
<span style="color: #009900;">&#123;</span>
  <span style="color: #003399;">String</span> getHello<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span>
&nbsp;
@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>MyComponent.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DefaultMyComponent
  <span style="color: #000000; font-weight: bold;">implements</span> MyComponent
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getHello<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;hello&quot;</span>;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>That&#8217;s all you need. We just created a MyComponent component contract (interface), and provided one implementation. The implementation is even annotated using Plexus annotation, that states &#8220;this class is a component with role MyComponent&#8221;. Since we say nothing about the hint of component, Plexus implicitly manages it as &#8220;default&#8221; implementation (one-and-only).</p>

<p>The consumer of this component does something like this:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>SomeOtherComponent.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AComponentConsumer
  <span style="color: #000000; font-weight: bold;">implements</span> SomeOtherComponent
<span style="color: #009900;">&#123;</span>
  @Requirement
  <span style="color: #000000; font-weight: bold;">private</span> MyComponent myComponent;
&nbsp;
  ...
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Here, with @Requirement annotation we declared a &#8220;requirement&#8221; (we need it injected) to the MyComponent interface. The Plexus will try to fulfill this requirement by looking up a component with role MyComponent, and hint &#8220;default&#8221; (implicit hint), since we did not say anything about needed hint.</p>

<p>For the second case (one contract, multiple implementations), the most simpler example is this:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> Archiver
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">void</span> archive<span style="color: #009900;">&#40;</span> <span style="color: #003399;">File</span> source, <span style="color: #003399;">File</span> archiveFile <span style="color: #009900;">&#41;</span> 
      <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>;
&nbsp;
    <span style="color: #000066; font-weight: bold;">void</span> unarchive<span style="color: #009900;">&#40;</span> <span style="color: #003399;">File</span> archiveFile, <span style="color: #003399;">File</span> destination <span style="color: #009900;">&#41;</span> 
      <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>;
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>and having component implementations like these:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>Archiver.<span style="color: #000000; font-weight: bold;">class</span>, hint<span style="color: #339933;">-</span><span style="color: #0000ff;">&quot;zip&quot;</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ZipArchiver
  <span style="color: #000000; font-weight: bold;">implements</span> Archiver
<span style="color: #009900;">&#123;</span>
  ...
<span style="color: #009900;">&#125;</span>
&nbsp;
@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>Archiver.<span style="color: #000000; font-weight: bold;">class</span>, hint<span style="color: #339933;">-</span><span style="color: #0000ff;">&quot;tgz&quot;</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TgzArchiver
  <span style="color: #000000; font-weight: bold;">implements</span> Archiver
<span style="color: #009900;">&#123;</span>
  ...
<span style="color: #009900;">&#125;</span>
&nbsp;
@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>Archiver.<span style="color: #000000; font-weight: bold;">class</span>, hint<span style="color: #339933;">-</span><span style="color: #0000ff;">&quot;7z&quot;</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SevenZArchiver
  <span style="color: #000000; font-weight: bold;">implements</span> Archiver
<span style="color: #009900;">&#123;</span>
  ...
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>The consumer of Archiver does something like this:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>SomeOtherComponent.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AComponentConsumer
  <span style="color: #000000; font-weight: bold;">implements</span> SomeOtherComponent
<span style="color: #009900;">&#123;</span>
  @Requirement<span style="color: #009900;">&#40;</span> hint<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;zip&quot;</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Archiver zipArchiver;
&nbsp;
  ...
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>In case above we &#8220;wired&#8221; the AComponentConsumer to support &#8220;zip&#8221; archives only. But we may do something like this:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>SomeOtherComponent.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AComponentConsumer
  <span style="color: #000000; font-weight: bold;">implements</span> SomeOtherComponent
<span style="color: #009900;">&#123;</span>
  @Requirement<span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>Archiver.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> List<span style="color: #339933;">&lt;</span>Archiver<span style="color: #339933;">&gt;</span> archivers;
&nbsp;
  ...
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>or</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@<span style="color: #003399;">Component</span><span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>SomeOtherComponent.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AComponentConsumer
  <span style="color: #000000; font-weight: bold;">implements</span> SomeOtherComponent
<span style="color: #009900;">&#123;</span>
  @Requirement<span style="color: #009900;">&#40;</span> role<span style="color: #339933;">=</span>Archiver.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Map<span style="color: #339933;">&lt;</span>String, Archiver<span style="color: #339933;">&gt;</span> archivers;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> archive<span style="color: #009900;">&#40;</span> <span style="color: #003399;">File</span> src, <span style="color: #003399;">File</span> dest <span style="color: #009900;">&#41;</span> 
    <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #003399;">String</span> destExt <span style="color: #339933;">=</span> getFileExtension<span style="color: #009900;">&#40;</span> dest <span style="color: #009900;">&#41;</span>;
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> archivers.<span style="color: #006633;">containsKey</span><span style="color: #009900;">&#40;</span> destExt <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      Archiver archiver <span style="color: #339933;">=</span> archivers.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> destExt <span style="color: #009900;">&#41;</span>;
&nbsp;
      archiver.<span style="color: #006633;">archive</span><span style="color: #009900;">&#40;</span> src, dest <span style="color: #009900;">&#41;</span>;
      ...
    <span style="color: #009900;">&#125;</span> 
    <span style="color: #000000; font-weight: bold;">else</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IOException</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Archive format unsupported!&quot;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>It is obvious, that in this example, Plexus will inject a Map&lt;String, Archiver&gt; into AComponentConsumer, where the String keys will be hints of components in the Map, and values will be Archiver instances with given key.</p>

<h3>So?</h3>

<p>So, why is this important? &#8212; you ask. Well, in Nexus, the &#8220;extension points&#8221; are simply taken, &#8220;marked&#8221; interfaces (roles), that will be automatically pulled by Plexus collection lookups similar to this last example. Marked by Nexus developers, and pointed out as &#8220;extension point&#8221; to the 3rd party plugin developers.</p>

<p>Actually, up to now, this was how Nexus supported &#8220;plugins&#8221;. &#8220;Plugins&#8221; and not plugins, up to now, the job of the developer was to code Plexus components, build them, provide Plexus descriptors for the plugin (usually by annotating the classes as above and using the plexus-component-metadata plugin, which embeds the descriptor into resulting JAR), and &#8220;drop it&#8221; into Nexus lib.</p>

<p>Since the developers implemented and marked their classes as @Component with roles that were looked up, after booting up Nexus with new JAR in it&#8217;s lib folder, Nexus was aware of these and would start using them as if they were a part of the &#8220;core&#8221;. Simple as that.</p>

<p>The downside of this approach is twofold:</p>

<ul>
  <li>3rd party developers are forced to use Plexus, plexus tooling, etc. Also, they must be aware of Nexus internals, for example that Repository components should be **prototypes**, and not **singletons**.</li>
  <li>the plugins are more like &#8220;extensions&#8221;, since they total and uncontrolled access to all of the Nexus internals, not just extension points.</li>
</ul>

<h2>The Idea</h2>

<p>In short:</p>

<ul>
  <li>let the &#8220;host application developers&#8221; mark and parametrize the extension points (@ExtensionPoint)</li>
  <li>let the &#8220;3rd party plugin developers&#8221; create extensions by implementing interfaces marked with @ExtensionPoint.</li>
  <li>provide IoC abilities for &#8220;3rd party pluging developers&#8221;</li>
  <li>let the &#8220;3rd party plugin developers&#8221; create their own managed beans, components with all the IoC benefits</li>
  <li>load the plugin in separate classloader</li>
</ul>

<p>Okay, let&#8217;s draft the idea: having &#8220;extension points&#8221;, which are all simple Java interfaces (component contracts) and are provided by &#8220;host application&#8221; developers (in this case Nexus developers). This is simple to understand: the <strong>host application developers</strong> are the one who know the what, where, and how about what is extensible within the application. Thus, we need to provide some means for developers, to mark their interfaces as @ExtensionPoint. Almost always, the case with components here is the &#8220;plural&#8221; case (one component interface, with multiple implementations, 3rd party developers just adding new ones to the pool of existing). But again, usually the host application developers are the ones who knos, and should provide information on extension points about instantiation details of the component implementations (singletons versus prototypes for example).</p></p>

<p>When the host application API has decorated interfaces (API), the **3rd party plugin developers** may kick in, by implementing @ExtensionPoints. All they have to do is pick a component interface marked as @ExtensionPoint, and implement it. That&#8217;s all. And what about IoC?</p>

<p>We decided to accept the @Inject project proposal at code.google.com, and use &#8220;meta-metadata&#8221; to decorate the components. Since @Inject already proposes a meta-metadata to make possible to annotate classes and use them across Guice and Spring, we thought making it work with Plexus would be nice too.</p>

<p>Thus, in short, 3rd party Nexus plugin developers should use @Inject annotations only. Naturally, when deployed to Nexus, their components will be &#8220;powered by Plexus&#8221; under the hud, but it&#8217;s not their problem and they should not care about it.</p>

<p>The Nexus Plugin Manager will have another great feature: **class loader separation**. Right now, since as I said, the plugin JAR was just dropped into Nexus lib folder, that implicitly means that plugins were doomed to use the same versions of dependencies that were already present in Nexus (newly introduced dependencies are fine, though). This led to the proliferation and over user of the Maven Shade plugin. Don&#8217;t get me wrong, I think this plugin is very-very useful, but it must be used with care (not to mention it&#8217;s flaw, that it &#8220;shades&#8221; stuff always under hidden package, instead to somewhere module specific place. Two jars with same shaded dependency may again clash).</p>

<p>One more thing: the @Inject proposal does not mention how to create new managed beans, they have no means to annotate a new component (well, in case of Guice it happens implicitly with @Inject, making the interface needed in binding).  This is where another new annotation comes in: @Managed. The @Managed annotation will be used on Java **interfaces only**, to mark them as component contracts.</p>

<p>So, in short:</p>

<ul>
  <li>Host application developers should point out the &#8220;extension point&#8221; interfaces in the apps. Also, they should provide as much &#8220;metadata&#8221; as possible about the instances of those components.</li>
  <li>plugin developers should only care about implementing those marked interfaces, and not fiddle with annotating them with some container-specific stuff</li>
  <li>use @Inject project annotations</li>
  <li>add ability to plugin developers to enjoy the benefits of IoC containers, and let them defined their own components (again, no Plexus needed).</li>
</ul>

<h2>Teaser</h2>

<p>Here is an example of a theoretical implementation of artifact virus scanner for Nexus. In short: we want to make sure no virus infected artifact will come in our Nexus instance. Internal deployments are considered &#8220;safe&#8221;, thus proxy requests are checked only.</p>

<p>These is what we need to implement this plugin:</p>

<ul>
  <li>A Virus scanner implementation (not shown here for example&#8217;s brevity&#8217;s sake)</li>
  <li>A Nexus RequestProcessor (extension point) implementation. RequstProcessor components are able to interact with every Nexus request, and stop their execution at different stages</li>
  <li>A Nexus RepositoryCustomizer (extension point) implementation, to inject the RequestProcessor from above to repositories we want</li>
</ul>

<p>We start with creating a managed component contract for Virus Scanner:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sample.plugin</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.InputStream</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.plugins.Managed</span>;
&nbsp;
@Managed
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> VirusScanner
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">boolean</span> hasVirus<span style="color: #009900;">&#40;</span> <span style="color: #003399;">InputStream</span> is <span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Then we implement it. This is a &#8220;singular&#8221; case, the newly introduced component contract interface has only one default implementation:</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sample.plugin</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.InputStream</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.inject.Named</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> XYVirusScanner
    <span style="color: #000000; font-weight: bold;">implements</span> VirusScanner
<span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> hasVirus<span style="color: #009900;">&#40;</span> <span style="color: #003399;">InputStream</span> is <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// DO THE JOB HERE</span>
        <span style="color: #000000; font-weight: bold;">return</span> resultOfTheScanning;
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Next, a RequestProcessor. It requires VirusScanner to do the work.   We are not making a decision until we  get to the content in shouldCache(). We are using the @Inject annotations to inject our newly created component.  Since VirusScannerRequestProcessor implements a Nexus extension point (they are &#8220;plural&#8221; components), we need to reference it later (see below in VirusScannerRepositoryCustomizer), we are &#8220;naming it&#8221; with the @Named annotation. </p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sample.plugin</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.IOException</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.inject.Inject</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.inject.Named</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.ResourceStoreRequest</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.access.Action</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.item.AbstractStorageItem</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.item.StorageFileItem</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.ProxyRepository</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.Repository</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.RequestProcessor</span>;
&nbsp;
@Named<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;virusScanner&quot;</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> VirusScannerRequestProcessor
    <span style="color: #000000; font-weight: bold;">implements</span> RequestProcessor
<span style="color: #009900;">&#123;</span>
    @Inject
    <span style="color: #000000; font-weight: bold;">private</span> VirusScanner virusScanner;
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> process<span style="color: #009900;">&#40;</span> <span style="color: #003399;">Repository</span> repository, ResourceStoreRequest request, <span style="color: #003399;">Action</span> action <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// don't decide until have content</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> shouldProxy<span style="color: #009900;">&#40;</span> ProxyRepository repository, ResourceStoreRequest request <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// don't decide until have content</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> shouldCache<span style="color: #009900;">&#40;</span> ProxyRepository repository, AbstractStorageItem item <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> item <span style="color: #000000; font-weight: bold;">instanceof</span> StorageFileItem <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            StorageFileItem file <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>StorageFileItem<span style="color: #009900;">&#41;</span> item;
&nbsp;
            <span style="color: #666666; font-style: italic;">// do a virus scan</span>
            <span style="color: #000000; font-weight: bold;">try</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000000; font-weight: bold;">return</span> virusScanner.<span style="color: #006633;">hasVirus</span><span style="color: #009900;">&#40;</span> file.<span style="color: #006633;">getInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
            <span style="color: #009900;">&#125;</span>
            <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span> <span style="color: #003399;">IOException</span> e <span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #666666; font-style: italic;">// handle it</span>
                <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">else</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Finally, we are creating a RepositoryCustomizer (also a &#8220;plural&#8221; component, but we don&#8217;t care about naming it), that will inject our RequestProcessor into repository instances we need. In this case, those are proxy repositories (the only ones able to fetch artifacts from remote repositories).</p>


<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.sample.plugin</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.inject.Inject</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.inject.Named</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.configuration.ConfigurationException</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.plugins.RepositoryCustomizer</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.ProxyRepository</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.Repository</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.sonatype.nexus.proxy.repository.RequestProcessor</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> VirusScannerRepositoryCustomizer
    <span style="color: #000000; font-weight: bold;">implements</span> RepositoryCustomizer
<span style="color: #009900;">&#123;</span>
    @Inject
    <span style="color: #000000; font-weight: bold;">private</span> @Named<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;virusScanner&quot;</span> <span style="color: #009900;">&#41;</span>
    RequestProcessor virusScannerRequestProcessor;
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> isHandledRepository<span style="color: #009900;">&#40;</span> <span style="color: #003399;">Repository</span> repository <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// handle proxy reposes only</span>
        <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">getRepositoryKind</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isFacetAvailable</span><span style="color: #009900;">&#40;</span> ProxyRepository.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> configureRepository<span style="color: #009900;">&#40;</span> <span style="color: #003399;">Repository</span> repository <span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">ConfigurationException</span>
    <span style="color: #009900;">&#123;</span>
        repository.<span style="color: #006633;">getRequestProcessors</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;virusScanner&quot;</span>, virusScannerRequestProcessor <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>That&#8217;s all for now. In the next part, we will make more in-depth explanations of the plugin API, and explain what is happening &#8220;behind the curtains&#8221;.  Have fun!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/sonatype?a=seSSNwPMwwY:deZRJ2AVKCU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=seSSNwPMwwY:deZRJ2AVKCU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/sonatype?i=seSSNwPMwwY:deZRJ2AVKCU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=seSSNwPMwwY:deZRJ2AVKCU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/sonatype?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/sonatype?a=seSSNwPMwwY:deZRJ2AVKCU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/sonatype?i=seSSNwPMwwY:deZRJ2AVKCU:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/sonatype/~4/seSSNwPMwwY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.sonatype.com/people/2009/06/writing-plugins-for-nexus-part-1/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.sonatype.com/people/2009/06/writing-plugins-for-nexus-part-1/</feedburner:origLink></item>
	</channel>
</rss>
