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

<channel>
	<title>Stuff and Things</title>
	<atom:link href="http://www.spudsoft.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.spudsoft.co.uk</link>
	<description>from SpudSoft</description>
	<lastBuildDate>Fri, 27 Jan 2012 14:33:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>LSNED49: Merged cell borders in Apache POI</title>
		<link>http://www.spudsoft.co.uk/2012/01/lsned49-merged-cell-borders-in-apache-poi/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned49-merged-cell-borders-in-apache-poi</link>
		<comments>http://www.spudsoft.co.uk/2012/01/lsned49-merged-cell-borders-in-apache-poi/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 14:33:27 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[Apache POI]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=532</guid>
		<description><![CDATA[When a merged cell with borders is created in Apache POI it tends to look like this: There is an FAQ on this here, but it&#8217;s not clear what&#8217;s actually required. I thought it meant create cells around the merged cell, but that is wrong (and would prohibit adjacent merged cells from having borders). Looking <a href='http://www.spudsoft.co.uk/2012/01/lsned49-merged-cell-borders-in-apache-poi/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>When a merged cell with borders is created in Apache POI it tends to look like this:<br />
<a href="http://www.spudsoft.co.uk/wp-content/uploads/2012/01/MergedCellBordersBroken.png"><img src="http://www.spudsoft.co.uk/wp-content/uploads/2012/01/MergedCellBordersBroken.png" alt="" width="346" height="120" class="alignnone size-full wp-image-534" /></a></p>
<p>There is an FAQ on this <a href="http://poi.apache.org/faq.html#faq-N100E3">here</a>, but it&#8217;s not clear what&#8217;s actually required.  I thought it meant create cells <em>around</em> the merged cell, but that is wrong (and would prohibit adjacent merged cells from having borders).</p>
<p>Looking at the file produced when a merged cell is given a border in Excel it is clear that what is actually required is the creation of more cells <em>within</em> the merged cell.</p>
<p>So, to achieve this:<br />
<a href="http://www.spudsoft.co.uk/wp-content/uploads/2012/01/MergedCellBorders.png"><img src="http://www.spudsoft.co.uk/wp-content/uploads/2012/01/MergedCellBorders.png" alt="" width="346" height="124" class="alignnone size-full wp-image-533" /></a></p>
<p>I have to:</p>
<ul>
<li>Create the cell at 1,1 and set the desired value for the merged cell.</li>
<li>Add a merged region from 1,1 to 3,3.</li>
<li>Create these cells without setting any value: [1,2]; [1,3]; [2,1]; [2,3]; [3,1]; [3,2]; [3,3].</li>
<li>Set top borders on the top cells, left borders on the left cells, right borders on the right cells and bottom borders on the bottom cells.<br />
        Note that for a 3&#215;3 merged cell this implies that each of the constituent cells has a unique cell style &#8211; in practice this may not be necessary as full borders on all cells should have the same effect.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2012/01/lsned49-merged-cell-borders-in-apache-poi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED48: Updating an eclipse plugin needs permission</title>
		<link>http://www.spudsoft.co.uk/2011/11/lsned48-updating-an-eclipse-plugin-needs-permission/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned48-updating-an-eclipse-plugin-needs-permission</link>
		<comments>http://www.spudsoft.co.uk/2011/11/lsned48-updating-an-eclipse-plugin-needs-permission/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 19:33:30 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=512</guid>
		<description><![CDATA[This is pretty obvious when you think about it, but of course, when it&#8217;s being annoying one doesn&#8217;t think about it enough. In order to instruct eclipse to refresh its cache of plugins it needs to be run with the &#8220;-clean&#8221; argument. So upgrading a plugin should be a case of: Delete the old plugin. <a href='http://www.spudsoft.co.uk/2011/11/lsned48-updating-an-eclipse-plugin-needs-permission/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>This is pretty obvious when you think about it, but of course, when it&#8217;s being annoying one doesn&#8217;t think about it enough.</p>
<p>In order to instruct eclipse to refresh its cache of plugins it needs to be run with the &#8220;-clean&#8221; argument.  So upgrading a plugin should be a case of:</p>
<ol>
<li>Delete the old plugin.</li>
<li>Copy the new plugin to the same location.</li>
<li>Run eclipse with the -clean argument</li>
</ol>
<p>I did that, and found that my plugin had been completely ignored.</p>
<p>The problem was that eclipse (in a fit of bad planning) maintains the plugin cache below its own directory, and if that directory is in a read-only location the -clean argument cannot work.</p>
<p>The fix is simply to ensure that eclipse can write to its own directory, either by changing the permissions or by running in an elevated manner (both are bad, but the former is much less bad).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/11/lsned48-updating-an-eclipse-plugin-needs-permission/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED47: BIRT Dynamic Number Formatting</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned47-birt-dynamic-number-formatting/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned47-birt-dynamic-number-formatting</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned47-birt-dynamic-number-formatting/#comments</comments>
		<pubDate>Sun, 30 Oct 2011 20:14:39 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[BIRT]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=499</guid>
		<description><![CDATA[There is a post on the BIRT DevShare that puts forward one approach for dynamic number formats in BIRT. In this post I put forward another approach that I claim is the &#8220;right way&#8221; , and then explain the merits of the other approach. Virgil&#8217;s approach allows you to write script that performs the formatting, <a href='http://www.spudsoft.co.uk/2011/10/lsned47-birt-dynamic-number-formatting/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>There is a <a href="http://www.birt-exchange.org/org/devshare/designing-birt-reports/711-birt-dynamic-number-formatting/">post on the BIRT DevShare that puts forward one approach for dynamic number formats in BIRT</a>.  In this post I put forward another approach that I claim is the &#8220;right way&#8221; <img src='http://www.spudsoft.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , and then explain the merits of the other approach.</p>
<p><a href="http://www.birt-exchange.org/org/devshare/designing-birt-reports/711-birt-dynamic-number-formatting/">Virgil&#8217;s approach</a> allows you to write script that performs the formatting, my approach is simply to change the number format each time it is rendered.</p>
<p>In my report I have a scripted dataset that outputs the following:</p>
<table>
<thead>
<tr>
<td>Currency</td>
<td>Amount</td>
<td>Rate</td>
</tr>
</thead>
<tr>
<td>£</td>
<td>3141.59265358979</td>
<td>1</td>
</tr>
<tr>
<td>$</td>
<td>3141.59265358979</td>
<td>0.620578379</td>
</tr>
<tr>
<td>¥</td>
<td>3141.59265358979</td>
<td>0.008192255</td>
</tr>
<tr>
<td>€</td>
<td>3141.59265358979</td>
<td>0.878428696</td>
</tr>
</table>
<p>(the Rate column is irrelevant for this solution, it&#8217;s just there so I can easily demonstrate that the Amount ends up as a number in Excel, by multiplying by the rates (which google told me were the correct exchange rates this morning <img src='http://www.spudsoft.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ))</p>
<p>The output I want from my report is:</p>
<table>
<thead>
<tr>
<td>Currency</td>
<td>Amount</td>
<td>Rate</td>
</tr>
</thead>
<tr>
<td>£</td>
<td>£3141.59</td>
<td>1</td>
</tr>
<tr>
<td>$</td>
<td>$3141.59</td>
<td>0.620578379</td>
</tr>
<tr>
<td>¥</td>
<td>¥3141.59</td>
<td>0.008192255</td>
</tr>
<tr>
<td>€</td>
<td>€3141.59</td>
<td>0.878428696</td>
</tr>
</table>
<p>Where the number format of the Amount column depends on the string listed in the Currency column.  To do this the OnRender event for the Data element on the report becomes (with plenty of debug spew):</p>
<pre class="brush: jscript; title: ; notranslate">
java.lang.System.err.println( 'onRender' );
java.lang.System.err.println( this.getRowData().getColumnValue('Currency') );
java.lang.System.err.println( this.getRowData().getColumnValue('Currency').charCodeAt(0) );
var currency = this.getRowData().getColumnValue('Currency');
this.getStyle().numberFormat = currency + "###0.00{RoundingMode=HALF_UP}";
</pre>
<h3>Why?</h3>
<p>The benefit of this approach (and the root of my claim that it&#8217;s the &#8220;right way&#8221;) is that it changes the number format, rather than replacing a number with a string.  For most emitters this is irrelevant (i.e. it makes absolutely no difference in HTML or PDF) and changing the data format like this <a href="https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/issue/6/emitters-cant-handle-dynamically-changing">might even confuse an emitter</a>; but if you are outputting to a spreadsheet there is a world of difference between a number and a string &#8211; and the latter is not much use if you want to multiply by the rate.</p>
<p>I would recommend using this approach if the field you are reformatting is numeric and you may want to have your report output to a spreadsheet and you know that your chose spreadsheet emitters won&#8217;t fall over, otherwise I&#8217;d go for <a href="http://www.birt-exchange.org/org/devshare/designing-birt-reports/711-birt-dynamic-number-formatting/">Virgil&#8217;s approach</a>.  Personally all my reports may be output as spreadsheets and <a href="http://www.spudsoft.co.uk/2011/10/the-spudsoft-birt-excel-emitters/">my emitter</a> will support this approach as soon as I upload the fix (as, I think, after limited testing, does the default Excel emitter), so I&#8217;ll go for this approach whenever the field is numeric and Virgil&#8217;s approach if it is not.<br />
Virgil&#8217;s approach is slightly simpler as it uses a complex expression rather than a script.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned47-birt-dynamic-number-formatting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED46: BIRT page-break-pagination broken</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned46-birt-page-break-pagination-broken/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned46-birt-page-break-pagination-broken</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned46-birt-page-break-pagination-broken/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 16:24:32 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[BIRT]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=489</guid>
		<description><![CDATA[There are three ways in which a BIRT emitter can handle pagination: no-pagination The emitter will be instructed to create a new page at the beginning of the report, and to end that page at the end of the report. This could be used for an HTML page that contains the entire report (it makes <a href='http://www.spudsoft.co.uk/2011/10/lsned46-birt-page-break-pagination-broken/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>There are three ways in which a <a href="http://www.eclipse.org/birt/phoenix/">BIRT</a> emitter can handle pagination:</p>
<ul>
<li>no-pagination<br />
        The emitter will be instructed to create a new page at the beginning of the report, and to end that page at the end of the report.<br />
        This could be used for an HTML page that contains the entire report (it makes more sense to let the browser handle pagination).
        </li>
<li>paper-size-pagination<br />
        The emitter will be told to start a new page based on the size of the paper and the size of elements added to that page.<br />
        It is the responsibility of the emitter to ensure that the things it renders are actually at the size that the layout engine expects, otherwise pagination will be a mess.<br />
        This is used for the PDF emitter, where the output is destined to end up on actual paper.
        </li>
<li>page-break-pagination<br />
        The emitter will be told to start a new page only in response to an explicit page-break (page-break-before or page-break-after) appearing in the report.<br />
        This is needed for my <a href="http://www.spudsoft.co.uk/?p=424">Excel emitters</a>, where I want to enable the report designer to lay elements out on separate Excel worksheets.
        </li>
</ul>
<p>There are two ways in which a BIRT report can be produced:</p>
<ul>
<li>A single RunAndRenderTask</li>
<li>A RunTask followed by a RenderTask</li>
</ul>
<p>The BIRT servlet defaults to using a RunAndRenderTask, whilst my own report server always uses separate Run and Render tasks.  </p>
<p>Whilst working on v0.3 of my <a href="http://www.spudsoft.co.uk/?p=424">Excel emitters</a>, where I changed the pagination from no-pagination (everything on a single worksheet) to page-break-pagination (separate sheets used in the control of the report design) I found that everything worked correctly when reports were run from the designer, but that my pagination was being ignored when run from my own API calls.<br />
I walked through the RenderTask source code and could not see how pagination would ever work correctly unless I set HTML_PAGINATION, but that would cause large tables to also generate page breaks, which the designer was not doing.</p>
<p>Eventually, after much scratching of head and debugging through BIRT code, I realised that the difference was that the designer was using a RunAndRenderTask whilst I was using a RenderTask.</p>
<p>The code for setting pagination in RunAndRender is completely different from that used in Render, and the result is that a RenderTask cannot support page-break-pagination.</p>
<p>I filed a <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=362245">bug</a>, but that still left me with broken pagination.</p>
<p>The solution was quite simple: use my own private RenderTask, that is identical to the BIRT RenderTask except that it has:</p>
<pre class="brush: java; first-line: 653; title: ; notranslate">
else if ( ExtensionManager.PAGE_BREAK_PAGINATION
        .equals( pagination ) )
{
    if ( !paged )
    {
        long pageNumber = iter.next( );
        if ( pageNumber != 1 )
        {
            layoutEngine.setLayoutPageHint( getPageHint(
                    pagesExecutor, pageNumber ) );
        }
        setFilteredPageNumber( filteredTotalPage,
                totalPage,
                pageNumber );
        layoutEngine.layout( executor, report, emitter, true );
    }
</pre>
<p>(the only change there is the final parameter of layout is changed from false to true).</p>
<p>I have to construct my RenderTask myself, rather than calling createRenderTask, but that&#8217;s simple enough:</p>
<pre class="brush: java; title: ; notranslate">
public IRenderTask createRenderTask( IReportDocument reportDocument ) {
    return new RenderTask( (ReportEngine)reportEngine, reportDocument );
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned46-birt-page-break-pagination-broken/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>LSNED45: How to deploy a jar with source and javadocs to a maven repository</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned45-how-to-deploy-a-jar-with-source-and-javadocs-to-a-maven-repository/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned45-how-to-deploy-a-jar-with-source-and-javadocs-to-a-maven-repository</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned45-how-to-deploy-a-jar-with-source-and-javadocs-to-a-maven-repository/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 21:17:01 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[nexus]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=481</guid>
		<description><![CDATA[Unfortunately there is no maven repository with jodconverter v3 snapshots in it. In order work around this I chose to install it into our local repository, which required a couple of changes to the pom. Enabling deployment The first step is to tell the pom the location of the repository: With that a simple &#8220;mvn <a href='http://www.spudsoft.co.uk/2011/10/lsned45-how-to-deploy-a-jar-with-source-and-javadocs-to-a-maven-repository/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Unfortunately there is no maven repository with <a href="http://code.google.com/p/jodconverter/">jodconverter</a> v3 snapshots in it.</p>
<p>In order work around this I chose to install it into our local repository, which required a couple of changes to the pom.</p>
<h2>Enabling deployment</h2>
<p>The first step is to tell the pom the location of the repository:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;project>
  ...
  &lt;distributionManagement>
    &lt;repository>
      &lt;id>our-repo&lt;/id>
      &lt;name>Our Internal Repository&lt;/name>
      &lt;url>http://our-nexus:8081/nexus/content/repositories/releases/&lt;/url>
    &lt;/repository>
    &lt;snapshotRepository>
      &lt;id>our-repo&lt;/id>
      &lt;name>Our Internal Snapshot Repository&lt;/name>
      &lt;url>http://our-nexus:8081/nexus/content/repositories/snapshots/&lt;/url>
    &lt;/snapshotRepository>
  &lt;/distributionManagement>
  ...
&lt;/project>
</pre>
<p>With that a simple &#8220;mvn deploy&#8221; will deploy the pom and jar to the repository, but it will ignore source and docs.</p>
<h2>Deploying Source and Javadocs</h2>
<p>Given that jodconverter is a nicely built maven project it&#8217;s a shame to exclude its source and docs from the repository, so to add them:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;project>
  ...
  &lt;build>
    &lt;plugins>
      ...
      &lt;plugin>
        &lt;groupId>org.apache.maven.plugins&lt;/groupId>
        &lt;artifactId>maven-source-plugin&lt;/artifactId>
        &lt;executions>
          &lt;execution>
            &lt;id>attach-sources&lt;/id>
            &lt;goals>
              &lt;goal>jar&lt;/goal>
            &lt;/goals>
          &lt;/execution>
        &lt;/executions>
      &lt;/plugin>
      &lt;plugin>
        &lt;groupId>org.apache.maven.plugins&lt;/groupId>
        &lt;artifactId>maven-javadoc-plugin&lt;/artifactId>
        &lt;executions>
          &lt;execution>
            &lt;id>attach-javadocs&lt;/id>
            &lt;goals>
              &lt;goal>jar&lt;/goal>
            &lt;/goals>
          &lt;/execution>
        &lt;/executions>
      &lt;/plugin>
    ...
    &lt;/plugins>
  &lt;/build>
  ...
&lt;/project>
</pre>
<p>After doing this you are still subject to the warnings about using 3rd party snapshots, but now you are in control of everything so you can ensure that you don&#8217;t get bitten.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned45-how-to-deploy-a-jar-with-source-and-javadocs-to-a-maven-repository/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED44: Sonatype Nexus does not support 3rd party snapshot repositories</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned44-sonatype-nexus-does-not-support-3rd-party-snapshot-repositories/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned44-sonatype-nexus-does-not-support-3rd-party-snapshot-repositories</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned44-sonatype-nexus-does-not-support-3rd-party-snapshot-repositories/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 09:41:53 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[nexus]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=477</guid>
		<description><![CDATA[The reasons for this are well documented (try here or here) but, when you need it, it&#8217;s irritating to discover that you cannot upload 3rd party snapshots to Nexus. I got as far as creating a new 3rd party snapshot repository and faffing around with it for far too long before discovering this. My solution <a href='http://www.spudsoft.co.uk/2011/10/lsned44-sonatype-nexus-does-not-support-3rd-party-snapshot-repositories/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>The reasons for this are well documented (try <a href="http://www.sonatype.com/people/2009/01/best-practices-for-releasing-with-3rd-party-snapshot-dependencies/">here</a> or <a href="https://issues.sonatype.org/browse/NEXUS-1036">here</a>) but, when you need it, it&#8217;s irritating to discover that you cannot upload 3rd party snapshots to Nexus.</p>
<p>I got as far as creating a new 3rd party snapshot repository and faffing around with it for far too long before discovering this.</p>
<p>My solution was (as <a href="http://www.sonatype.com/people/2009/01/best-practices-for-releasing-with-3rd-party-snapshot-dependencies/">suggested</a>, though i didn&#8217;t find that out until later) to check out the source, build it myself and install it to my local repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned44-sonatype-nexus-does-not-support-3rd-party-snapshot-repositories/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED43: How to have relative path in a Flat File Data Source in BIRT</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned43-how-to-have-relative-path-in-a-flat-file-data-source-in-birt/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned43-how-to-have-relative-path-in-a-flat-file-data-source-in-birt</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned43-how-to-have-relative-path-in-a-flat-file-data-source-in-birt/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 19:46:33 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[BIRT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ReportEngine]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=465</guid>
		<description><![CDATA[In BIRT if you define a Flat File Data Source you have to provide it with an absolute path, and if you try to cheat by going in to the XML and changing the path to a relative one the data simply won&#8217;t be found. This is very frustrating if you want to ship a <a href='http://www.spudsoft.co.uk/2011/10/lsned43-how-to-have-relative-path-in-a-flat-file-data-source-in-birt/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>In BIRT if you define a Flat File Data Source you have to provide it with an absolute path, and if you try to cheat by going in to the XML and changing the path to a relative one the data simply won&#8217;t be found.<br />
This is very frustrating if you want to ship a set of data with a report, in my case as one of the tests for my <a href="http://www.spudsoft.co.uk/?p=424">Excel Emitters</a>.</p>
<p>The solution is a little bit of scripting in the beforeFactory method:</p>
<pre class="brush: jscript; title: ; notranslate">
var path;
if( reportContext.getHttpServletRequest() != null ) {
	var request = reportContext.getHttpServletRequest().getParameterMap();
	path = request.get( "__report" )[0].toString();
}
if( path!= null){
	if( path.contains( "/" ) ) {
		path = path.substring( 0, path.lastIndexOf( "/" ) );
	} else if( path.contains( "\\" ) ) {
		path = path.substring( 0, path.lastIndexOf( "\\" ) );
	}
}
// java.lang.System.err.println( "resourcePath = " + path );
this.getDataSource( "Mission Data Source" ).setPrivateDriverProperty( "HOME", path );
</pre>
<p>That&#8217;s great if you are running your report from a normal environment (where reportContext.getHttpServletRequest() will not be null), but what if you are running it from a custom ReportEngine host?<br />
Well, in that case you need to add the path to the report to the appContext:
<pre class="brush: java; title: ; notranslate">
if( filepath != null ) {
    @SuppressWarnings("unchecked")
    Map&lt;String,Object> appContext = (Map&lt;String,Object>)reportRunTask.getAppContext();
    if( appContext == null ) {
        appContext = new HashMap&lt;String,Object>();
        reportRunTask.setAppContext(appContext);
    }
    appContext.put("__report", filepath);
}
</pre>
<p>Which only leaves the small problem of how to find the correct path to the report design file.<br />
In a normal environment finding the path to the report design file shouldn&#8217;t be too difficult, but if the report design is a resource in an OSGi bundle (i.e. in an eclipse plugin unit test) you have a few more hoops to jump through:</p>
<pre class="brush: java; title: ; notranslate">
String filepath = null;
if( Activator.getContext() != null ) {
    URL bundleLocation = new URL(Activator.getContext().getBundle().getLocation());
    // System.err.println( "Activator.getContext().getBundle().getLocation() = " + bundleLocation );
    String bundleLocationFile = bundleLocation.getFile();
    if(bundleLocationFile.startsWith("file:/")) {
        bundleLocationFile = bundleLocationFile.substring(6);
    }
    // System.err.println( "bundleLocationFile = " + bundleLocationFile );

    URL resourceLocation = this.getClass().getResource( filename );
    String resourceLocationFile = resourceLocation.getFile();
    // System.err.println( "resourceLocationFile = " + resourceLocationFile );

    filepath = bundleLocationFile + "bin" + resourceLocationFile;
    // System.err.println( "filepath = " + filepath );
}
</pre>
<p>It&#8217;s worth having those println method calls in there so you see what you are getting for the bundle and resource location &#8211; the values will almost certiainly change with different OSGi hosts, but that works for my plugins unit tests.</p>
<p>And of course, now the beforeFactory script needs modifying to pick up from either the Servlet request or the appContext:</p>
<pre class="brush: jscript; title: ; notranslate">
var path;
if( reportContext.getHttpServletRequest() != null ) {
	var request = reportContext.getHttpServletRequest().getParameterMap();
	path = request.get( "__report" )[0].toString();
} else if( reportContext.getAppContext() != null ) {
	path = reportContext.getAppContext().get( "__report" );
}
if( path!= null){
	if( path.contains( "/" ) ) {
		path = path.substring( 0, path.lastIndexOf( "/" ) );
	} else if( path.contains( "\\" ) ) {
		path = path.substring( 0, path.lastIndexOf( "\\" ) );
	}
}
// java.lang.System.err.println( "resourcePath = " + path );
this.getDataSource( "Mission Data Source" ).setPrivateDriverProperty( "HOME", path );
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned43-how-to-have-relative-path-in-a-flat-file-data-source-in-birt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The SpudSoft BIRT Excel Emitters</title>
		<link>http://www.spudsoft.co.uk/2011/10/the-spudsoft-birt-excel-emitters/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-spudsoft-birt-excel-emitters</link>
		<comments>http://www.spudsoft.co.uk/2011/10/the-spudsoft-birt-excel-emitters/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 19:45:30 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Stuff And Things]]></category>
		<category><![CDATA[Apache POI]]></category>
		<category><![CDATA[BIRT]]></category>
		<category><![CDATA[Excel]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=424</guid>
		<description><![CDATA[There are, to my knowledge, five existing emitters for BIRT that output reports in a format understood by Excel. Unfortunately all four of them have significant issues for my purposes: The built-in emitter. The built-in emitter does not output Excel format files, it outputs files in an XML format that Excel can understand, as a <a href='http://www.spudsoft.co.uk/2011/10/the-spudsoft-birt-excel-emitters/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>There are, to my knowledge, five existing emitters for BIRT that output reports in a format understood by Excel. Unfortunately all four of them have significant issues for my purposes:</p>
<ul>
<li>The built-in emitter.<br />
The built-in emitter does not output Excel format files, it outputs files in an XML format that Excel can understand, as a result newer versions of Excel complain whenever the files are opened.<br />
The files also have problems with page layout that I could not work around (specifically wide reports would be cut off) and do not display charts or logos.</li>
<li>The Tribix emitter.<br />
The <a href="http://sourceforge.net/projects/tribix/">Tribix emitter</a> solves many of the problems with the built-in emitter, but tries too hard to produce an output document that looks identical to the original report.<br />
As a result the output spreadsheets contain a lot of very small rows/columns that are introduced purely to make the content line up visibly as it would on a PDF. Unfortunately this results in headers appearing in one column with data appearing in another &#8211; sparse crosstabs are particularly bad in this regard with data failing to line up &#8211; which all means that the output from the Tribix emitters is not actually very useful as a spreadsheet.</li>
<li>The Arctorus emitters.<br />
When I last tried them, the <a href="http://marketplace.eclipse.org/content/arctorus-xlsx-birt-emitter">Arctorus emitters</a> behaved suspiciously similarly to the Tribix emitter, but also support XLSX and cost money.<br />
It is my understanding that their v3 emitters no longer attempt pixel-perfect layout, and that may make them the best around, but they still cost money and I believe they still create/merge rows/columns for layout.</li>
<li>The Actuate 11 emitter.<br />
Unfortunately I haven&#8217;t tried the new <a href="http://www.birt-exchange.org/org/wiki/index.php?title=Actuate_11">Actuate 11</a> emitter, because it comes as part of the Actuate 11 system that is priced out of our range.</li>
<li>RameshS&#8217; emitter<br />
A fellow entrant in the <a href="http://www.birt-exchange.org/org/news-events/resources/?articleid=23230">Getting Started with BIRT contest</a>.<br />
My understanding is that <a href="http://www.birt-exchange.org/org/devshare/designing-birt-reports/1421-native-excel-emitter-plugin-for-birt/">RameshS&#8217; emitter</a> is based on the built in source code, but writing to native XLS files (I don&#8217;t think it handles <em>XLSX</em>, but it&#8217;s not clear from my reading).<br />
I have not tried this emitter, but my expectation is it still creates/merges rows/columns for layout, and its use of Excel formatting seems to be more primitive than mine (images are restricted to a single cell, auto row heights rely on Excel behaviour) &#8211; but it claims to have smaller file sizes than Tribix, which may mean it beats me too.<br />
If your only complaint about the built in emitter is the file format then give this a go.
</li>
</ul>
<p>So, after discovering <a href="http://poi.apache.org/">Apache POI</a> and realising that <a href="http://digiassn.blogspot.com/2007/08/birt-writing-emitter.html">BIRT emitters are not so complicated after all</a>, I set about writing an Excel emitter that met our needs.<br />
The design aims for the SpudSoft BIRT emitter are:</p>
<ul>
<li>It must be useful as a spreadsheet, cells should all line up, there should be no blank rows/columns for formatting, there should be no page breaks.</li>
<li>It must open in Excel without complaint, preferably support both XLS and XLSX files.</li>
<li>It must display images (logos and charts are required).</li>
<li>It must include any formatting that does not clash with the other requirements.</li>
<li>It must work in the BIRT runtime environment, as well as in eclipse.</li>
</ul>
<h3>Known Limitations</h3>
<p>Obviously, given that I&#8217;m explicitly favouring spreadsheetiness over formatting, there are going to be some limitations:</p>
<ul>
<li>BIRT allows you to put multiple things into a cell (i.e. two different labels), my emitter will try to output the content of both, but the formatting will only be an amalgamation.<br />
In particular this means that nested tables (or tables within grids) will not display correctly.<br />
I&#8217;m open to suggestions as to how to resolve this, but I haven&#8217;t actually got any reports that use nested tables yet, so I haven&#8217;t worried about it.</li>
<li>BIRT allows you to have two tables next to each other, horizontally or vertically, with different row/column height/widths, on a spreadsheet I should just take the maximum.</li>
<li>Formatting will be handled on an as-needs basis &#8211; when I have a report that needs support for something I&#8217;ll make sure I can have it <img src='http://www.spudsoft.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>Column widths will often be left at their default, rather than trying to persuade things to fit (because headings and images often overlap).</li>
</ul>
<p>If you find more limitations or other issues please let me know (either via this blog or by filing an issue on bitbucket), and if can&#8217;t live with these limitations let me know how you think I should resolve them and I&#8217;ll see what I can do.</p>
<p>In short, my emitter will produce good results with all the reports I&#8217;ve seen (better, I hope, than BIRT or Tribix), but I could easily produce a report that it could not cope with at all (that BIRT and Tribix probably could cope with).</p>
<h3>Download</h3>
<p>The emitter is all GPLv3 and the source is available on <a href="https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters" target="_blank">BitBucket</a>.<br />
The binary is available from <a href="https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/downloads">https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/downloads</a>.<br />
And instructions for installation are available <a href="https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/wiki/Home">here</a>.</p>
<p>Before throwing that binary directly into your production environment you are warned to take good notice of the version number!<br />
You could well be the first person other than myself to use the emitter, it is bound to have faults ranging from slight limitations to major crashers.<br />
If you do find issues with it please report them at <a href="https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/issues">https://bitbucket.org/yaytay/spudsoft-birt-excel-emitters/issues</a>.</p>
<h3>Update v0.3</h3>
<p>Version 0.3 generates new Excel sheets in response to explicit page-breaks.<br />
Sheets will take their names from the last named table seen on that page (if there are no named tables and there is only a single sheet that sheet will be named with the title of the report).</p>
<p>There is a <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=362245">bug in BIRTs RenderTask</a> that prevents page-break-pagination working. There are two ways around this:</p>
<ul>
<li>The simple option is to use the RunAndRenderTask, which does paginate correctly.</li>
<li>If you need to use a separate RenderTask the only option I could find is to <a href="http://www.spudsoft.co.uk/?p=489">write a custom RenderTask</a>.</li>
</ul>
<h3>Update v0.4</h3>
<p>Version 0.4 has been through a substantial refactor in order to make it possible to implement nested tables without having spaghetti code.<br />
The result is more explicitly an FSM than it was previously, with state being represented by an instance of a &#8220;handler&#8221; class &#8211; typically a new handler is created in a startThing method call and removes itself in the corresponding endThing method call.<br />
The main changes on top of the refactor are:</p>
<ul>
<li>Nested Tables<br />
Currently these only work if the child table is the only thing on given row (more specifically, there must be no other cells on the same row, so the cell must be merged across columns). This is a significant limitation, but does allow a great many designs to work that couldn&#8217;t work before.<br />
Note that my emitter still does not (and never will) merge or insert columns to try to make things line up.</li>
<li>Rotated Text<br />
Large crosstabs are often unwieldly in spreadsheets because the column headings tend to be quite long, meaning that columns are wide and thus very little of the sheet is visible at any time.<br />
The fix for this in the spreadsheet world is to rotate the column headings to an angle so multiple headings overlap and the columns can be much narrower.<br />
This option is now available from my emitter.<br />
BIRT does not have any built in option for rotating text, and any generic solution would have to generate the text as an image, which is not much use for a spreadsheet.<br />
To inform the emitter that text should be rotated you have to set a User Property called &#8220;ExcelEmitter.Rotation&#8221; on the text/label control that is to be rotated, for example:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;label id="57">
    &lt;list-property name="userProperties">
        &lt;structure>
            &lt;property name="name">ExcelEmitter.Rotation&lt;/property>
            &lt;property name="type">string&lt;/property>
        &lt;/structure>
    &lt;/list-property>
    &lt;property name="ExcelEmitter.Rotation">60&lt;/property>
    &lt;property name="textAlign">right&lt;/property>
    &lt;text-property name="text">Flights&lt;/text-property>
&lt;/label>
</pre>
</li>
<li>Auto Column Widths<br />
An oft-requested feature from my <a href="http://gtisolutions.co.uk/">No1 client</a>, and one that I&#8217;ve been putting off because reports as spreadsheets often don&#8217;t work with auto-column widths as they often have titles in the early rows that are expected to flow over multiple cells (without using merged cells).<br />
My solution is to only base auto column widths on cells in the details band of tables, and for performance reasons I only consider the first 4 rows there.<br />
Auto column widths will not make columns narrower (if you want them narrower specify the width in the report design) and will not be used at all if the width is specified in the report design.
</li>
<li>Row Grouping<br />
A simple change &#8211; table groups in the report are now configured as row groups in Excel.
</li>
</ul>
<h3>Update v0.5</h3>
<p>A bit anti-climactic after version 0.4, version 0.5 has a bug fix to set the top and bottom margins correctly and one new feature:</p>
<ul>
<li>Force Auto Column Widths<br />
After adding support for auto column widths and turning it off by default I go and find a situation where it needs to be be turned on &#8211; specifically if you have columns that you want hidden unless they contain data.  By forcing auto column width calculations the column widths can be set to zero and they will only become wider if there is data to fill them.<br />
As with text rotation, this is controlled by a User Property, this time a boolean property called &#8220;ExcelEmitter.ForceAutoColWidths&#8221;.
</li>
</ul>
<h3><a name="footnote">Footnote</a></h3>
<p>Finally I&#8217;d like to thank my employer, <a href="http://gtisolutions.co.uk/">GTI Recruiting Solutions</a>, for permitting me to release this.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/the-spudsoft-birt-excel-emitters/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>LSNED42: DX/Y in ClientAnchor for images in Apache POI spreadsheets</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned41-dxy-in-clientanchor-for-images-in-apache-poi-spreadsheets/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned41-dxy-in-clientanchor-for-images-in-apache-poi-spreadsheets</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned41-dxy-in-clientanchor-for-images-in-apache-poi-spreadsheets/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 18:00:05 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[Apache POI]]></category>
		<category><![CDATA[ClientAnchor]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=439</guid>
		<description><![CDATA[It&#8217;s taken me quite a while to get this right, and until yesterday I was using something that was close, but wrong, so here&#8217;s the details. When images are placed in a spreadsheet using Apache POI they are located using an instance of the ClientAnchor class. The ClientAnchor consists of eight values, accessed by getters/setters: <a href='http://www.spudsoft.co.uk/2011/10/lsned41-dxy-in-clientanchor-for-images-in-apache-poi-spreadsheets/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s taken me quite a while to get this right, and until yesterday I was using something that was close, but wrong, so here&#8217;s the details.</p>
<p>When images are placed in a spreadsheet using Apache POI they are located using an instance of the <a href="http://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/ClientAnchor.html">ClientAnchor</a> class.<br />
The ClientAnchor consists of eight values, accessed by getters/setters:</p>
<ul><code>short Col1;<br />
short Col2;<br />
int Row1;<br />
int Row2;<br />
int Dx1;<br />
int Dx2;<br />
int Dy1;<br />
int Dy2;</code></ul>
<p>Between them these eight values represent the top left and bottom right corner of the image.  The Row/Col values are the (zero-based) indices of the cells in which the image starts/ends, and the Dx/Dy values are the offsets within those cells.  Hopefully this diagram makes this clearer:<br />
<img src="http://www.spudsoft.co.uk/wp-content/uploads/2011/10/ClientAnchor.png" alt="ClientAnchor diagram" /></p>
<p style="margin-bottom:0">
Here the Row/Col fields have the following values:</p>
<table style="width:25%">
<tr>
<td style="padding:0">Col1</td>
<td style="padding:0">1</td>
</tr>
<tr>
<td style="padding:0">Row1</td>
<td style="padding:0">2</td>
</tr>
<tr>
<td style="padding:0">Col2</td>
<td style="padding:0">5</td>
</tr>
<tr>
<td style="padding:0">Row2</td>
<td style="padding:0">5</td>
</tr>
</table>
<p>Unfortunately the DX/DY values have different units for XLS (HSSF) and XLSX (XSSF) spreadsheets, so I&#8217;ll handle them separately.</p>
<h3>HSSFClientAnchor</h3>
<p>For the HSSFClientAnchor the DX/DY values represent fractions of the total size of the cell, and for added fun they are different fractions.<br />
The value of DX is in [0, 1023] and the value of DY is in [0, 255].<br />
So if the offset of the image is known in millimetres, and the size of the column is known in millimetres, calculation of DX is as simple as:</p>
<pre class="brush: java; title: ; notranslate">
return (int)( 1023.0 * widthMM / colWidthMM );
</pre>
<h3>XSSFClientAnchor</h3>
<p>For the XSSFClientAnchor the DX/DY values are in EMUs (that&#8217;s <a href="http://en.wikipedia.org/wiki/English_Metric_Unit#DrawingML">EMUs</a> not <a href="http://en.wikipedia.org/wiki/Emu">emus</a>).  There are, by definition, 36000 EMUs per millimetre, so the calculation of DX becomes:</p>
<pre class="brush: java; title: ; notranslate">
return (int)( 36000 * widthMM );
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned41-dxy-in-clientanchor-for-images-in-apache-poi-spreadsheets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LSNED41: XSSFWorkbook.write(OutputStream) closes the stream, whilst HSSFWorkbook.write(OutputStream) doesn&#8217;t.</title>
		<link>http://www.spudsoft.co.uk/2011/10/lsned41-xssfworkbook-writeoutputstream-closes-the-stream-whilst-hssfworkbook-writeoutputstream-doesnt/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lsned41-xssfworkbook-writeoutputstream-closes-the-stream-whilst-hssfworkbook-writeoutputstream-doesnt</link>
		<comments>http://www.spudsoft.co.uk/2011/10/lsned41-xssfworkbook-writeoutputstream-closes-the-stream-whilst-hssfworkbook-writeoutputstream-doesnt/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 07:02:36 +0000</pubDate>
		<dc:creator>yaytay</dc:creator>
				<category><![CDATA[Learn something new every day]]></category>
		<category><![CDATA[Apache POI]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.spudsoft.co.uk/?p=432</guid>
		<description><![CDATA[Not a problem, just something that you might need to be aware of, in Apache POI XSSFWorkbook.write(OutputStream) closes the stream, whilst HSSFWorkbook.write(OutputStream) doesn&#8217;t. I found this because I have a TemporaryFile class that cleans itself up after being closed (more specifically, after the OutputStream has been closed you can get an InputStream, and after that <a href='http://www.spudsoft.co.uk/2011/10/lsned41-xssfworkbook-writeoutputstream-closes-the-stream-whilst-hssfworkbook-writeoutputstream-doesnt/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Not a problem, just something that you might need to be aware of, in <a href="http://poi.apache.org/">Apache POI</a> XSSFWorkbook.write(OutputStream) closes the stream, whilst HSSFWorkbook.write(OutputStream) doesn&#8217;t. </p>
<p>I found this because I have a TemporaryFile class that cleans itself up after being closed (more specifically, after the OutputStream has been closed you can get an InputStream, and after that has been closed it deletes the file) &#8211; and it only permits one OutputStream to be got.<br />
It was trivial to work around the issue, I just had to keep hold of the OutputStream rather than ask for it again, that way I close the same OutputStream (which does nothing) and the TemporaryFile is unaffected.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spudsoft.co.uk/2011/10/lsned41-xssfworkbook-writeoutputstream-closes-the-stream-whilst-hssfworkbook-writeoutputstream-doesnt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

