<?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>Aptivate &#124; A Blog for ICT4D &#187; Software</title>
	<atom:link href="http://blog.aptivate.org/category/software/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.aptivate.org</link>
	<description>International I.T. Development</description>
	<lastBuildDate>Wed, 01 Feb 2012 14:09:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.6</generator>
		<item>
		<title>Content indexing in Django using Apache Tika</title>
		<link>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/</link>
		<comments>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 13:12:44 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=992</guid>
		<description><![CDATA[For the Documents module of our new open-source Generic Intranet, we need to be able to extract the text content and metadata from various kinds of documents: PDF files Microsoft Office DOC, XLS and PPT files and the new XML equivalents, DOCX, XLSX and PPTX. I found various tools online to help extract this text, [...]]]></description>
			<content:encoded><![CDATA[<p>For the Documents module of our new open-source <a href="https://github.com/aptivate/intranet">Generic Intranet</a>, we need to be able to extract the text content and metadata from various kinds of documents:</p>
<ul>
<li>PDF files</li>
<li>Microsoft Office DOC, XLS and PPT files</li>
<li>and the new XML equivalents, DOCX, XLSX and PPTX.</li>
</ul>
<p>I found various tools online to help extract this text, largely thanks to Stack Overflow <a href="http://superuser.com/questions/165978/command-line-tool-in-linux-to-extract-text-from-word-excel-powerpoint-or-co">here</a> and <a href="http://stackoverflow.com/questions/888784/extract-text-from-a-powerpoint-ppt-or-pptx-file">here</a>. This ended up with a hodgepodge of tools:</p>
<ul>
<li><a href="http://www.unixuser.org/~euske/python/pdfminer/">PDF Miner</a> for PDF files</li>
<li><a href="http://github.com/mikemaccana/python-docx/tarball/master">python-docx</a> for DOCX files</li>
<li><a href="http://silvercoders.com/en/products/doctotext/">DocToText</a> for PPTX, XLSX and PPT files</li>
<li><a href="http://www.winfield.demon.nl/">antiword</a> for DOC files</li>
</ul>
<p>There were a number of problems with this hodgepodge:</p>
<ul>
<li>I was <strong>unable to find</strong> any Python or command-line solution for <strong>old Excel (XLS) files</strong><strong>;</strong></li>
<li>These solutions did not extract metadata, only document text;</li>
<li>The choice of which tool to use depends on the MIME type returned by the <a href="http://www.darwinsys.com/file/">file(1)</a> command, which varies depending on the OS (Debian/Ubuntu or CentOS) and which version of the library is installed</li>
</ul>
<p><a href="http://stackoverflow.com/questions/2239459/python-based-document-metadata-parser">Another Stack Overflow post</a> recommended Apache Tika for metadata extraction. It appears to support all the document formats that we need, and to have auto-detection of the document format, which solves all the MIME type problems as well. However, it introduces a new problem: it&#8217;s written in Java, which is hard to access from Python.</p>
<p>Luckily I found some <a href="http://redmine.djity.net/projects/pythontika/wiki">instructions</a> for building a Python wrapper around Tika, using some tools that I&#8217;d never heard of, and this seemed like a good approach. Unfortunately the installation process is very non-standard, which would not fit in with our fabric-based automated deployment process, and would make it harder for users to install the Intranet themselves.</p>
<p>The instructions are somewhat outdated at the time of writing, as they refer to Tika version 0.7, while 1.0 has been released. I was unable to register for an account to update that page, so I wrote to the author with the details that I discovered, and will also document here that the following command works for me:</p>
<pre>python ../jcc/jcc/__main__.py \
        --include /usr/share/java/org.eclipse.osgi.jar \
        --jar tika-parsers-1.0.jar \
        --jar tika-core-1.0.jar \
        java.io.File java.io.FileInputStream \
        java.io.StringBufferInputStream \
        --package org.xml.sax \
        --include tika-app-1.0.jar \
        --python tika --version 1.0 --reserved asm</pre>
<p>I was able to go further than this, and package Tika in a way that makes it easy to install with Pip, and thus integrate with our deployment process.</p>
<p>The wrapper is written using JCC, which works by generating and compiling C++ code that links to the Java classes, and then a Python wrapper around that C++. This means that it needs to be recompiled for each platform, so I couldn&#8217;t just distribute a binary blob with the Intranet (I had the same problem with DocToText above).</p>
<p>The version of setuptools on our servers doesn&#8217;t support JCC&#8217;s <a href="http://lucene.apache.org/pylucene/jcc/documentation/install.html#shared">shared library mode</a>. JCC dies with an error if it&#8217;s not explicitly disabled or the patch applies. I couldn&#8217;t do either of these as part of our standard deployment process. So I <a href="https://github.com/aptivate/jcc">patched JCC</a> to disabled shared mode, since we don&#8217;t need it anyway. I also added some patches to allow various <code>setup.py</code> commands used by <code>pip</code> to be forwarded through JCC to the <code>setup</code> function call.</p>
<p>This seems to be enough to allow you to install JCC like this:</p>
<pre>pip install git+git://github.com/aptivate/jcc.git</pre>
<p>I also wrote a setup.py file that handles pip&#8217;s command line invokations and passes the necessary options to JCC, and JCC&#8217;s invocation of the setup function. This seems to be enough to install the package using pip:</p>
<pre>pip install git+git://github.com/aptivate/python-tika.git</pre>
<p>and you can use the last parameter as a package specification in pip_packages.txt, or whatever you pass to pip -r.</p>
<p>You can find the pip-installable Tika package, complete with <a href="http://repo1.maven.org/maven2/org/apache/tika/">Tika 1.0 JAR files</a>, in our <a href="https://github.com/aptivate/python-tika">python-tika</a> repository on Github. This will save you the work of downloading and compiling Tika and all of its dependencies. I have started a <a href="http://mail-archives.apache.org/mod_mbox/lucene-pylucene-dev/201202.mbox/%3Calpine.DEB.2.02.1202011310060.5732%40lap-x201%3E">discussion</a> with the JCC developers about merging these changes into the upstream project.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>8 bit alpha png optimisation with pngquant</title>
		<link>http://blog.aptivate.org/2011/06/28/8-bit-alpha-png-optimisation-with-pngquant/</link>
		<comments>http://blog.aptivate.org/2011/06/28/8-bit-alpha-png-optimisation-with-pngquant/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 15:37:57 +0000</pubDate>
		<dc:creator>Jay Alvarez</dc:creator>
				<category><![CDATA[Design and Usability]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[graphics]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=866</guid>
		<description><![CDATA[It looks like we may have found an alternative to great png optimisation at last, pngquant.  We really struggled with this issue on the Reaction Scorecards website as the homepage had some graphics with fine lines and alpha transparency which were proving difficult to optimise. In the past I have used Adobe fireworks which seemed [...]]]></description>
			<content:encoded><![CDATA[<p>It looks like we may have found an alternative to great png optimisation at last, <a href="http://www.libpng.org/pub/png/apps/pngquant.html"><strong>pngquant</strong></a>.  We really struggled with this issue on the <a href="http://ihpresults.net/">Reaction Scorecards</a> website as the  homepage had some graphics with fine lines and alpha transparency which  were proving difficult to optimise.</p>
<p>In the past I have used Adobe fireworks which seemed unrivalled in the open source world but <strong><a href="http://www.libpng.org/pub/png/apps/pngquant.html"><strong>pngquant</strong></a></strong> is just great.</p>
<p>The  command line tool allows you to squish the <strong>32bit png</strong> files output from  Inkscape into <strong>8 bit</strong> files with any number of colours from 2 to 255. To  make the test I used an <strong>11.9 kB</strong> inkscape file which when processed using <strong><a href="http://www.libpng.org/pub/png/apps/pngquant.html"><strong>pngquant</strong></a></strong> and 24 colours was perfectly acceptable and now had only a <strong>3.1 kB</strong> file size. Yippee!!. I&#8217;m a happy bunny</p>
<p><a rel="attachment wp-att-871" href="http://blog.aptivate.org/2011/06/28/8-bit-alpha-png-optimisation-with-pngquant/bunny-fs8/"><img class="size-full wp-image-871 alignnone" style="background-image: url(http://blog.aptivate.org/wp-content/uploads/2011/06/gradient-bg.jpg); margin: 20px; background-repeat:repeat-x;" title="happy transparent 8bit bunny" src="http://blog.aptivate.org/wp-content/uploads/2011/06/bunny-fs8.png" alt="happy transparent 8bit bunny" width="272" height="248" /></a></p>
<p><em>(MyPaint bunny 39 kB -&gt; Gimp bunny 53 kB -&gt; happy pngquant bunny 13 kB)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/06/28/8-bit-alpha-png-optimisation-with-pngquant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Move over microsoft: Design&#8217;s going open source</title>
		<link>http://blog.aptivate.org/2011/05/19/move-over-microsoft-designs-going-open-source/</link>
		<comments>http://blog.aptivate.org/2011/05/19/move-over-microsoft-designs-going-open-source/#comments</comments>
		<pubDate>Thu, 19 May 2011 10:19:58 +0000</pubDate>
		<dc:creator>Jay Alvarez</dc:creator>
				<category><![CDATA[Design and Usability]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=784</guid>
		<description><![CDATA[I’ve been designing websites since 1999 but switching from Microsoft Windows to Ubuntu has been one of those pivotal experiences worth sharing. Joining Aptivate as the in-house designer recently has given me the opportunity to challenge some pretty old work-flows and move towards a totally open source design practice. Aptivate work almost exclusively with open [...]]]></description>
			<content:encoded><![CDATA[<p><strong></strong>I’ve been designing websites since 1999 but switching from <a href="http://www.microsoft.com/windows/explore/default.aspx" target="_blank">Microsoft Windows</a> to <a href="http://www.ubuntu.com/" target="_blank">Ubuntu</a> has been one of those pivotal experiences worth sharing. Joining  Aptivate as the in-house designer recently has given me the opportunity  to challenge some pretty old work-flows and move towards a totally open  source design practice.</p>
<p>Aptivate  work almost exclusively with open source software so it seems a great  idea to give Microsoft the push, and frankly I’d had enough of waiting 9  minutes for my laptop to reboot. That’s enough time for making 6 people  a cup of tea, water the plants and rearrange the desk; all good things  ONCE a day not 5 times when the PC crashes. 3 years of filling up with  junk makes a Windows PC very very sluggish and an unhappy designer with a  tidy workspace.</p>
<h2>Changing over &#8211; a gradual process</h2>
<p>Leaving  Microsoft was never going to a straight switch. Leaving a web platform  if you are dependent on it for your income is a scary thing.</p>
<p>Since  i cut my design teeth on Apple Macs and Adobe software in 1995, I have  moved gradually to Windows in a bid to be one step closer to the end  user who on the whole use this platform. I was still, however heavily  dependent on Adobe products, primarily <a href="http://www.adobe.com/products/fireworks.html" target="_blank">Fireworks</a> and <a href="http://www.adobe.com/products/dreamweaver.html" target="_blank">Dreamweaver </a>for interface design and development, but also <a href="http://www.adobe.com/products/illustrator.html" target="_blank">Illustrator </a>for vector graphics and <a href="http://www.adobe.com/products/photoshop.html" target="_blank">Photoshop</a> for photo editing. I know they are good, but really? couldn’t I achieve a good web result without them?</p>
<h2>Open source alternatives within Windows.</h2>
<p>Going  back a bit to before the anger towards the laptop really kicked in.  Finding open source alternatives was an exciting challenge. These were  readily available for Windows so I didn’t have to switch, just try them  out. I found a really useful website <a href="http://www.osalt.com/" target="_blank">www.osalt.com</a> which helps you to find open source alternatives to commercial software.</p>
<h3>Web development &#8211; Aptana 2</h3>
<p>Essentially I wanted an html/css editor with code completion, ftp client and project manager.. I tried <a href="http://www.osalt.com/amaya" target="_blank">Amaya</a>,  <a href="http://www.osalt.com/bluefish" target="_blank">Bluefish </a><a href="http://www.osalt.com/kompozer" target="_blank">KompoZer</a> and <a href="http://www.osalt.com/seamonkey" target="_blank">Mozilla SeaMonkey</a> which all had great features, but none of them did ALL the things I  wanted together and I really was a bit spoilt by having them all rolled  into one with Dreamweaver.  Finally I found <a href="http://www.osalt.com/aptana" target="_blank">Aptana 2</a> which whilst a bit fiddly to get started with seemed to have everything I needed, hurray!</p>
<ul>
<li> Best thing about Aptana  &#8211;  has to be the available plugin support for different types of project  such as php, python/django, javascript, svn and git. It’s very  comprehensive.</li>
</ul>
<ul>
<li>What I miss the most from Dreamweaver &#8211;  nothing&#8230; had I still been dependent on the WYSIWYG editor in  Dreamweaver then I could argue that this would be a bit deal, but since  most of my work is now with dynamic database driven sites, I tend to use  <a href="http://getfirebug.com/" target="_blank">Firebug</a> to make visual tweaks before committing them to code.</li>
</ul>
<h3>Web design &#8211; Inkscape</h3>
<p>A  key part of my work involves developing brand assets, icons and other  vector graphics for both web and print design. For this I had depended  on Illustrator. Quite quickly however I discovered <a href="http://www.inkscape.org/" target="_blank">Inkscape</a> . What an amazing product! it’s a bit clunky but it lets me do 90% of  the key design tasks I did in Illustrator and 60% of tasks I used to do  in Fireworks.  Essentially it is the easiest transition I have made on  this journey and means that I now only use Inkscape for designing for  the web.</p>
<ul>
<li>Best thing about Inkscape &#8211; The  ability to export 32 bit png files from any selection, the page or  object.  The other best bit is all the native SVG features I have yet to  discover!</li>
<li> What I miss the most from Illustrator &#8211; nothing worth mentioning.</li>
<li>What I miss the most from Fireworks &#8211; Image  optimisation &#8211; no image editing software that I’m aware of does a  better job of compressing and optimising all nature of image files than  Fireworks. It creates an 8 bit alpha png with a tiny size and smooth,  edging where transparent bits kick in. This for me is the single most  important missing feature of any open source alternative. Inkscape needs  a good image optimising tool.</li>
</ul>
<h3>Photo editing &#8211; Gimp</h3>
<p>Scaling,  cropping, optimising photos; that’s a big part of creating photographic  content for a website. Mainly I leave that to the end user but  sometimes I create photo-based graphics too.<br />
<a href="http://www.gimp.org/" target="_blank">Gimp</a> seems the most logical choice, as it suggests so itself, but I’m not  finding it intuitive and it seems to crash more often than not.  Fireworks has a limited range of bitmap editing tools compared to  Photoshop but integrates really well within the context of creating an  interface design as bitmap and vector graphic objects live happily on  the same layer or multiple layers. Now there are several open source  alternatives for this work such as but I’ll admit that I’m not finding a  great solution and again it’s the optimisation issue that makes me  frustrated.</p>
<h3>Designing for Low Bandwidth</h3>
<p>If  we need to create websites with small file sizes for countries with low  bandwidth then we need powerful optimisers. I found that Fireworks was  great because of the high compression rates achievable which result in  files more than half the size achievable using other programmes, open  source or commercial. So here is a proposal for a future project for  Aptivate &#8211; create an 8 bit Alpha transparency image optimiser that  challenges Fireworks.</p>
<h2>Switching to Ubuntu</h2>
<p>A  couple of months later I reformatted and partitioned the hard drive of  my Dell Precision 9300 workstation. I still wanted access to Windows, so  did a dual boot with an extra partition for shared files. Apart from my  video card packing in unexpectedly (nothing to do with the installation  I’m assured) , the installation went without a hitch. I was amazed by  how intuitive the Ubuntu interface was. Using the software install  centre, I was able to quickly and directly install all the applications I  needed. Start up and shut down was a mere seconds and as I was in  production mode within a couple of hours. I was more than happy to find  <a title="Dropbox" href="http://dropbox.com">Dropbox</a>, <a href="http://www.skype.com">Skype</a> and <a href="http://get.adobe.com/uk/reader/">Acrobat Reader</a> were also available. All in all it was  pain free, and&#8230; Ubuntu is actually graphically beautiful (not something I had anticipated at all).</p>
<h3>The dreaded Terminal</h3>
<p>Well  it’s inevitable even for a designer. The WYSIWYG addicts worst fear,  THE TERMINAL!!! agghh!! . A Baptism of code fire at Aptivate, no namby  pamby intro here. I had pulled down the designer’s defence gate and in  trickled (and sometimes poured) an endless stream of code, configuration  files, settings, database fixtures, tables, smart tricks and speedy  scripts, screen sharing and networking wizardry. Ah! then I had a cup of  tea. I’ll be a terminal ninja one day.</p>
<h3>Do I miss Windows?</h3>
<p>I  don’t miss windows. I booted into it shortly after installing Ubuntu,  and found it an empty experience, like going back to a house I you’ve  just moved out of but still have keys to. Can’t find the kettle to make a  cup of tea so not staying. I recently installed <a href="http://www.virtualbox.org/" target="_blank">virtual box </a>and now run several different versions of Windows XP to help me cross-browser debug CSS.</p>
<h3>Moving forward</h3>
<p>Apart  from using my new open source toolbox to help Aptivate refresh it’s  current website, there are things I want to do. It would be great to  contribute to the open source community and generally help to improve  already great products such as Inkscape. I’ve already started submitting  <a href="http://www.inkscape.org/" target="_blank">Inkscape</a> icons to the <a href="http://www.openclipart.org/" target="_blank">Open Clip Art Library</a> and it would be great if we developed the image optimiser I mentioned  before. There is also a lot of potential in interactive svg’s which  would be great to explore especially since Internet Explorer 9 supports  them.. oh Microsoft you are never forgotten&#8230;</p>
<p>If you are designer reading this, and fancy getting involved with Aptivate’s open source efforts somehow, <a href="http://contact-us/" target="_blank">get in touch</a>.  If you are a developer and have a secret optimiser up your sleeve,  please let us feed you and keep you amused because we want it!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/05/19/move-over-microsoft-designs-going-open-source/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Offline Websites and Low Bandwidth Simulator in Go</title>
		<link>http://blog.aptivate.org/2011/02/16/offline-websites-and-low-bandwidth-simulator-in-go/</link>
		<comments>http://blog.aptivate.org/2011/02/16/offline-websites-and-low-bandwidth-simulator-in-go/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 11:29:38 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Appropriate Technology]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Digital Resilience]]></category>
		<category><![CDATA[Education]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Offline]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[bandwidth]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=768</guid>
		<description><![CDATA[Jon Thompson writes about Jeff Allen's interesting new work on tools for working with low bandwidth:

<ul><li>A web proxy that simulates low bandwidth connections, and</li>
<li>one that can be fed prepackaged content repositories to serve up when offline, or on the wrong end of a slow Internet connection.</li>
</ul>

Content management systems could be extended to integrate better with these tools and make sites automatically offlineable.]]></description>
			<content:encoded><![CDATA[<p>Jon Thompson writes about <a href="http://aidworkerdaily.com/2011/02/09/jeff-go-and-some-chicken-and-biscuits/">Jeff Allen&#8217;s interesting new work on tools for working with low bandwidth</a>:</p>
<blockquote><p>Jeff continues to try and solve the low bandwidth/high latency problems that aid workers face in the field every day and that we encountered in Indonesia. We all know the joy of VSAT networks that slow to a crawl because either some folks on the team are downloading stuff they shouldn’t be downloading or all the computers are infected with bandwidth sucking viruses. It appears Jeff has moved one step closer to sorting out some of the problems surrounding bandwidth optimization by utilizing the Go programming language.</p>
<p>Rather than try and explain to you what Jeff has done I’ll let you read ‘A rate-limiting HTTP proxy in Go‘ and ‘How to control your HTTP transactions in Go‘ and sort out what he is talking about. Hopefully, this post will bait Jeff into leaving a lengthy comment that explains exactly what the hell he is up to.</p></blockquote>
<p>My understanding is that Jeff is developing two useful tools:</p>
<ul>
<li><a href="http://blog.nella.org/?p=833">A web proxy that simulates low bandwidth connections</a>, similar to the <a href="loband.org/loband/simulator.jsp">Loband Simulator</a>. Jeff&#8217;s version is probably more accurate than ours because it doesn&#8217;t need to modify the web page, but ours might be easier for non-developers to try out, because you don&#8217;t have to install any software.</li>
<li>A web proxy that can be fed <a href="http://aidworkerdaily.com/2011/02/09/jeff-go-and-some-chicken-and-biscuits/#comment-49355">prepackaged content repositories to serve up</a>, so that you can take pre-prepared content (offline websites) with you into the field, and browse them through the proxy as though you were online.</li>
</ul>
<p>People have been trying to make offlineable websites for a long time. Some of the best examples so far are using entirely client-side (in-browser) technology, such as the <a href="http://www.logcluster.org/tools/log">Logistics Operational Guide</a>, developed by the World Food Programme for the Logistics Cluster, which can <a href="http://log.logcluster.org/portable.html">run entirely offline</a> using Google Gears.</p>
<p>Gears had a lot of potential for developers to create offlineable websites, but Google has abandoned its future development in favour of the open standard HTML5, which is not ready yet. So there&#8217;s no obvious and future-proof way to develop offlineable websites at the moment. Jeff&#8217;s proxy, combined with a spidering system, could be one way to download an entire site, even if it wasn&#8217;t designed to be downloaded by the developers.</p>
<p>Another important potential comes from content management systems (CMS) such as <a href="http://wordpress.com">WordPress</a>, <a href="http://drupal.org">Drupal</a> and <a href="http://joomla.org">Joomla</a>. More and more websites are developed using such systems, rather than coded from scratch. The systems know all of the pages on the site, and the links between them, and could easily build an offlineable version of the site for download into Gears, HTML5 or Jeff&#8217;s proxy. And one plugin could potentially enable thousands of sites to be offlineable, especially if it was included in the CMS distribution and enabled by default.</p>
<p>A few wikis such as MediaWiki, MoinMoin, DocuWiki and JSPWiki have a <a href="http://www.mediawiki.org/wiki/Talk:WikiText_Transfer_Protocol">programming interface</a> (XML-RPC or WebDAV) that allows a smart client to download pages in their original text format, which could make them more efficient to store offline and also potentially editable offline. Jeff&#8217;s proxy could be extended to support sites built in such wikis automatically. There are still some limitations to this approach:</p>
<ul>
<li>The pages would not look the same as the online versions, since the styling wouldn&#8217;t be downloaded and the effects of CMS plugins would not be visible;</li>
<li>It would probably still be quite slow to download an entire site this way, by spidering, without server-side support for downloading multiple pages at once;</li>
<li>Few websites are built out of Wikis, so the potential maximum reach is limited compared to better support for WordPress, Drupal or Joomla.
</li>
</ul>
<p>Anyway, I wish I knew Go, and had time to hack on Jeff&#8217;s proxy tools.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/02/16/offline-websites-and-low-bandwidth-simulator-in-go/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Capturing Prepared Statement Parameters</title>
		<link>http://blog.aptivate.org/2010/11/03/capturing-prepared-statement-parameters/</link>
		<comments>http://blog.aptivate.org/2010/11/03/capturing-prepared-statement-parameters/#comments</comments>
		<pubDate>Wed, 03 Nov 2010 13:04:24 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[rita]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/2010/11/03/capturing-prepared-statement-parameters/</guid>
		<description><![CDATA[I&#8217;m using Hibernate for a project, and sometimes I have problems with saving records because the values in the Java object don&#8217;t fit within the database columns (e.g. large floating point numbers in a DECIMAL column, or long strings). Hibernate often executes the INSERT operations in batches, which means that the actual failing values are [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m using Hibernate for a project, and sometimes I have problems with saving records because the values in the Java object don&#8217;t fit within the database columns (e.g. large floating point numbers in a DECIMAL column, or long strings).</p>
<p>Hibernate often executes the INSERT operations in batches, which means that the actual failing values are not visible, because the PreparedStatement API gives you no way to get them out, and Hibernate doesn&#8217;t let you intercept them being set. The insert can also happen long after you created the object. These facts makes it very hard to find and fix the invalid data.</p>
<p>I decided to write a wrapper for PreparedStatement to capture the values being set by Hibernate, and a new Batcher to wrap the PreparedStatements returned by the driver in wrapper objects of my class. I was about to start laboriously writing yet another delegator class that does the boring work of implementing 100 methods and delegating each one individually to the wrapped class. I love Java so much.</p>
<p>Luckily I stopped and figured that someone might have done this before, and indeed I found <a href="http://www.jroller.com/holy/entry/a_logging_wrapper_around_preparedstatement">an implementation by Holy</a>. I adapted it slightly and <a href="http://rita.logscluster.org/changeset/1769">integrated it into RITA</a>.</p>
<p>To replace the default batcher with my own, to enable the wrapping of statements, I just had to add the following line to my Hibernate configuration properties:</p>
<pre>
hibernate.jdbc.factory_class = org.wfp.rita.db.CapturingBatcher$Factory
</pre>
<p>Thanks, Jakob Holy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/11/03/capturing-prepared-statement-parameters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Consistency, Portability and Backwards Compatibility</title>
		<link>http://blog.aptivate.org/2010/10/06/consistency-portability-and-backwards-compatibility/</link>
		<comments>http://blog.aptivate.org/2010/10/06/consistency-portability-and-backwards-compatibility/#comments</comments>
		<pubDate>Wed, 06 Oct 2010 14:13:20 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[backwards compatibility]]></category>
		<category><![CDATA[consistency]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[pmacct]]></category>
		<category><![CDATA[pmGraph]]></category>
		<category><![CDATA[portability]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=717</guid>
		<description><![CDATA[Michał Purzyński reported a problem with our pmGraph software, when using a PostgreSQL database: I&#8217;d like to report a bug &#8211; pmgraph is unable to get data from postgresql database to which nfacctd is writing&#8230; javax.servlet.ServletException: org.postgresql.util.PSQLException: ERROR: column "src_port" does not exist It turns out that pmacct, up to and including version 0.12.4, uses [...]]]></description>
			<content:encoded><![CDATA[<p>Michał Purzyński reported a problem with our <a href="http://www.aptivate.org/Projects.BMOTools.pmGraph.html">pmGraph</a> software, when using a <a href="http://www.postgresql.org/">PostgreSQL</a> database:</p>
<blockquote><p>
I&#8217;d like to report a bug &#8211; pmgraph is unable to get data from postgresql database to which nfacctd is writing&#8230; </p>
<p><code>javax.servlet.ServletException: org.postgresql.util.PSQLException:<br />
ERROR: column "src_port" does not exist</code>
</p></blockquote>
<p>It turns out that <a href="http://www.pmacct.net/">pmacct</a>, up to and including version 0.12.4, uses a different column name for the source port if the database is MySQL or SQLite:</p>
<pre>
if (!strcmp(config.type, "mysql") || !strcmp(config.type, "sqlite3")) {
  strncat(insert_clause, "src_port", SPACELEFT(insert_clause));
  strncat(where[primitive].string, "src_port=%u", SPACELEFT(where[primitive].string));
}
else {
  strncat(insert_clause, "port_src", SPACELEFT(insert_clause));
  strncat(where[primitive].string, "port_src=%u", SPACELEFT(where[primitive].string));
}
</pre>
<p>I really wish applications wouldn&#8217;t change their behaviour arbitrarily like this. To work around it, we would have to hard-code the database types in pmGraph as well, or add an option to switch the column names. Since pmGraph uses JDBC to access the database, it&#8217;s not even obvious which driver names are accessing an (underlying) MySQL or SQLite database. So we need to switch the column names, but if we can get pmacct fixed then we can ease the pain for new users in future.</p>
<p>I <a href="http://www.mail-archive.com/pmacct-discussion%40pmacct.net/msg01653.html">reported a bug</a> to Paolo Lucente, the lead developer of pmacct, through their mailing list. Paolo agreed to change this behaviour, even though it will break backwards compatibility. We spent some time discussing how to do this in a way that would minimise any impact on existing users. </p>
<p>To do this, we took advantage of pmacct&#8217;s existing system of database table versioning, which means that you can still use the oldest table structures, even with the most recent version of pmacct.  Paolo <a href="http://www.mail-archive.com/pmacct-discussion%40pmacct.net/msg01656.html">agreed</a> to create a new schema version that uses the same column names for all databases, so that pmacct will <a href="http://www.mail-archive.com/pmacct-discussion%40pmacct.net/msg01659.html">remain backwards-compatible for all users</a> unless they deliberately choose to change their database schema version.</p>
<p>As we chose to standardise on the PostgreSQL column names, the column names will change for MySQL users between schema versions 7 and 8, so we&#8217;ll need to add a configuration option to pmGraph to allow users to choose whether they want the old or the new column names. This is the very same switch that I wanted to avoid in pmacct, but pmGraph has fewer users so it has less impact.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/10/06/consistency-portability-and-backwards-compatibility/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Digital Photography on Linux</title>
		<link>http://blog.aptivate.org/2010/09/02/digital-photography-on-linux/</link>
		<comments>http://blog.aptivate.org/2010/09/02/digital-photography-on-linux/#comments</comments>
		<pubDate>Thu, 02 Sep 2010 08:12:39 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=623</guid>
		<description><![CDATA[Many people think that digital photography on Linux is much harder than on Windows or Macintosh. This is a typical comment: As a hobby I&#8217;m a photographer, so I do lots of graphic work as editing for invites, posters, mag covers etc. does any one know of a software that will be as great as [...]]]></description>
			<content:encoded><![CDATA[<p>Many people think that digital photography on Linux is much harder than on Windows or Macintosh. This is a typical comment:</p>
<blockquote><p>As a hobby I&#8217;m a photographer, so I do lots of graphic work as editing for invites, posters, mag covers etc. does any one know of a software that will be as great as photoshop for linux (Ubuntu), not Gimp, Gimp is very limited. I tried using WINE but it doesnt work well, very slow.</p></blockquote>
<p>It was true for a long time that working with digital photos on Linux was difficult. The main problem was that the most popular software that users are familiar with, Photoshop and Lightroom, is simply not available for Linux (due to unfortunate business decisions by Adobe).</p>
<p>There have been open source alternatives to Photoshop for a while, notably Gimp, but Gimp is difficult to use and the interface is quite annoying:</p>
<blockquote><p>
I&#8217;d say the major limiting factor is the desire to slit your wrists while arguing with the unwieldy interface layout.</p></blockquote>
<p>Luckily today I came across (thanks to Alastair Otter of GLUG) this excellent article:</p>
<p><a href="http://blog.worldlabel.com/2010/photography-with-open-source-linux.html">Photography with Open Source / Linux</a></p>
<p>This includes detailed descriptions of the many applications available, most of which I hadn&#8217;t heard of before, and look forward to trying. I&#8217;ve been particularly impressed by Adobe Lightroom&#8217;s ease of use and powerful histogram correction features, and I was considering buying a copy even though it doesn&#8217;t run on Linux, but I will definitely try Darktable now.</p>
<p>For users who really, really have to have a Photoshop user interface, <a href="http://www.gimpshop.com/">GimpShop</a> may help.</p>
<p>And before you say &#8220;this is not work related&#8221;, I&#8217;ve often needed to edit photographs to prepare brochures, promotional materials and for website work <img src='http://blog.aptivate.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>It seems that digital photography on Linux has made excellent progress in the last year, and I&#8217;m very happy to see it.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/09/02/digital-photography-on-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple Cisco VPN How-To</title>
		<link>http://blog.aptivate.org/2010/08/03/simple-cisco-vpn-how-to/</link>
		<comments>http://blog.aptivate.org/2010/08/03/simple-cisco-vpn-how-to/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 21:24:42 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[cisco]]></category>
		<category><![CDATA[encryption]]></category>
		<category><![CDATA[networking]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=605</guid>
		<description><![CDATA[One of our fellow Humanitarian Centre organisations, Engineers Without Borders UK (EWB), asked for our help in setting up a virtual private network (VPN), so that their remote workers can access their file server. This is something that ought to be really simple. It&#8217;s probably the most common use case of VPNs, Windows has a [...]]]></description>
			<content:encoded><![CDATA[<p>One of our fellow <a href="http://www.humcentre.org">Humanitarian Centre</a> organisations, <a href="http://www.ewb-uk.org">Engineers Without Borders UK</a> (EWB), asked for our help in setting up a virtual private network (VPN), so that their remote workers can access their file server.</p>
<p>This is something that ought to be really simple. It&#8217;s probably the most common use case of VPNs, Windows has a built-in VPN client, and Cisco routers can be used as VPN servers. EWB want it to be simple, because they have non-technical remote workers. It turned out to be much harder and take much longer than I expected.</p>
<h3>Information Overload</h3>
<p>One of the biggest problems was the lack of useful information, and the profusion of useless. The information fell mainly into four categories:</p>
<ul>
<li>Cisco marketing materials touting the benefits of VPNs and their expensive Concentrator and WebVPN products;</li>
<li>Cisco knowledge base articles describing the setup of complex VPN scenarios;</li>
<li>Cisco command references with little or no details on what each command actually does, or how to use them together;</li>
<li>Cisco exam study sites with inaccurate, out-of-date or cookie-cutter command sequences, with even less explanation of what the commands actually do.</li>
</ul>
<p>Because I couldn&#8217;t find what I was looking for, and had to work it out the hard way, I&#8217;ve written it up in the hope that it will help others.</p>
<p>I would recommend any organisations that simply want to share files to seriously consider a file-sharing service like <a href="http://dropbox.com">DropBox</a> or raw <a href="http://s3.amazonaws.com">Amazon S3</a> instead of a local file server and VPN. In many cases the low upload bandwidth of ADSL connections, combined with internal office use of the connection. will make a VPN impractically slow, especially compared to Amazon&#8217;s unlimited upload and download bandwidth. But EWB already had the file server and they just wanted to access it remotely, not to change how they work.</p>
<p>Our scenario is simple: an internal office network with private IP addresses, a Cisco 1800 router providing ADSL connectivity for the office, and remote field workers running Windows desktops.</p>
<h3>Getting the Client</h3>
<p>For simplicity, we and EWB had hoped to use the built-in VPN client on Windows, which would remove the need to download and install software on the remote workers&#8217; machines. But unfortunately the Cisco 1800 does not support this. Windows uses L2TP over IPSEC for modern, secure VPNs, as a replacement for the old insecure PPTP protocol. But Cisco has crippled the L2TP support in this router, and it only supports raw IPSEC. Only their more expensive routers support serving L2TP over IPSEC, allowing simple direct connections from Windows.</p>
<p>Raw IPSEC is the only remaining option on this router, but it&#8217;s difficult to configure due to its complexity, and the number of choices that need to be made. The standard requires both sides to have the same settings configured, but provides no way to do this automatically. Manual configuration would make life very hard for the remote workers. To solve this problem, Cisco has a non-standard protocol for auto-configuration of the clients:</p>
<blockquote><p>
Establishing a VPN connection between two routers can be complicated, and it typically requires tedious coordination between network administrators to configure the two routers&#8217; VPN parameters.</p>
<p>The Cisco Easy VPN Client feature eliminates much of this tedious work by implementing Cisco&#8217;s Unity Client protocol, which allows most VPN parameters to be defined at [the] IPSec server. </p>
<p><a href="http://www.cisco.com/en/US/products/hw/routers/ps221/prod_configuration_guide09186a008007cfa7.html#wp101952">Cisco Easy VPN Client for the Cisco 1700 Series Routers</a>
</p></blockquote>
<p>So we needed to find a replacement client that was easy to use and could talk to the Cisco. Preferably a free one.</p>
<p>Then we discovered that although Cisco&#8217;s own VPN client is technically free, you can&#8217;t actually download it without a support contract, which neither we nor EWB have.</p>
<p>In the end we found that if you go to Cisco&#8217;s <a href="http://tools.cisco.com/support/downloads/pub/ImageList.x?relVer=5.0.07.0290&#038;mdfid=281940730&#038;sftType=VPN+Client+Software&#038;optPlat=Windows&#038;nodecount=2&#038;edesignator=null&#038;modelName=Cisco+VPN+Client+v5.x&#038;treeMdfId=268438162&#038;treeName=Security&#038;modifmdfid=&#038;imname=&#038;hybrid=&#038;imst=&#038;lr=Y">VPN client software page</a>, find the filename of the latest version of the client, and Google it, you&#8217;ll find that <a href="http://www.google.co.uk/search?q=vpnclient-win-msi-5.0.07.0290-k9.exe&#038;ie=utf-8&#038;oe=utf-8&#038;aq=t&#038;rls=com.ubuntu:en-GB:unofficial&#038;client=firefox-a">several people</a> have had enough of this nonsense and posted the client online, so it can be downloaded.</p>
<p>Of course it&#8217;s important to be aware of the potential for viruses in copies that you download from random sites on the Internet, as well as fake download sites that lead you around in circles of free registrations, credit card details and pop-up porn adverts. <a href="http://samsten.net/work/cvpnc/">This site</a> worked fine for me, but it may have been taken down by Cisco&#8217;s attack dogs by the time you read this.</p>
<h3>Security with Obscurity</h3>
<p>We decided to choose a configuration that trades some security for ease of use. So instead of authenticating with certificates, we used pre-shared keys. The VPN server has its own login system anyway, which provides an additional layer of security once the remote user is connected to the VPN.</p>
<h3>Names and Addresses</h3>
<p>Connecting clients need to be allocated an IP address to use over the VPN. We could have used public IPs, or private IPs in the same subnet (with <a href="http://www.ciscocatalyst.info/en/US/docs/ios/ipaddr/command/reference/iad_arp.html#wp1013235">proxy ARP</a>), but we chose to use private IPs in a different subnet. This makes the routing easier, as clients and local network servers will know that they have to route the traffic via the router anyway, and it allows EWB to implement stricter network access policies for VPN clients, if they wish. </p>
<p>We needed to create a local pool (not a DHCP pool) to draw these addresses from:</p>
<pre>
ip local pool vpnpool 192.168.2.100 192.168.2.200
</pre>
<h3>Keys to the Kingdom</h3>
<p>We created an ISAKMP (IKE) policy to specify the authentication method and the level of encryption to be used for negotiation of IPSEC Security Associations (SAs). We chose to make this the first, highest priority policy, and to use AES-256 encryption (strong and fast), Group 2 (1024-bit) Diffie-Hellman key exchange, and pre-shared keys for client authentication as noted above:</p>
<pre>
crypto isakmp policy 1
 encr aes 256
 authentication pre-share
 group 2
</pre>
<p>Then we specified the pre-shared key itself. This is the only thing that stops random clients on the Internet from connecting to your local network, so it&#8217;s even more important than a strong wireless network key. Of course this is not the real key:</p>
<pre>
crypto isakmp key ThisKeyMustBeKeptSecret address 0.0.0.0 0.0.0.0
</pre>
<p> We specify that any IP address can use it by using the wildcard address, <code>0.0.0.0 0.0.0.0</code>.</p>
<h3>At the End of the Tunnel</h3>
<p>It seems to be common in corporate environments that, when a user is connected to a VPN, all of their Internet traffic is routed through the VPN. It certainly makes it easier for the network administrators, as they don&#8217;t have to define specific routes for the tunnel, but it wastes their bandwidth and makes Internet access much slower for the remote workers, so we decided not to do this.</p>
<p>Just routing a single subnet through a tunnel is called a <em>split tunnel</em>. I couldn&#8217;t find simple documentation on setting it up, so I used the <a href="http://www.cisco.com/en/US/docs/ios/sec_secure_connectivity/configuration/guide/sec_easy_vpn_rem.html#wp1060585">Cisco Easy VPN Remote example</a>, extracting just the bits we needed to route only the 192.168.1.0/24 subnet through the tunnel.</p>
<p>First we have to create an access control list (ACL) that defines, on the local (source address) side, what traffic clients should route into the tunnel:</p>
<pre>
ip access-list extended ewb_office_split_tunnel
 remark Defines which local (office) networks a remote VPN client will route to
 permit ip 192.168.1.0 0.0.0.255 192.168.2.0 0.0.0.255
</pre>
<p>I&#8217;m not sure if the second half of the ACL is actually necessary. It doesn&#8217;t appear to make any difference if I specify <code>any</code> instead of <code>192.168.2.0 0.0.0.255</code>.</p>
<h3>Client Configuration</h3>
<p>We use Cisco&#8217;s EzVPN (Unity) protocol, as described earlier, to configure connecting clients automatically. To do this, we have to tell the server what configuration should be sent to clients when they connect:</p>
<pre>
crypto isakmp client configuration group EWB
 key ThisKeyMustBeKeptSecret
 dns 192.168.1.1
 wins 192.168.1.2
 pool vpnpool
 acl ewb_office_split_tunnel
 netmask 255.255.255.0
</pre>
<p>A little explanation about what these options do:</p>
<dl>
<dt>crypto isakmp client configuration group [name]</dt>
<dd>The <em>name</em> must match the <strong>group name</strong> that the client uses when it connects. This is how the server decides which configuration to send to the client.</dd>
<dt>key</dt>
<dd>For some reason the client needs to be told what key to use, even though it&#8217;s already been entered by the user, and the client knows it because it wouldn&#8217;t be able to get this far in the negotiation without it!
</dd>
<dt>dns</dt>
<dd>Tells the client which DNS server to use, for resolving local (private) hostnames, or resolving inside the split horizon. You can specify a second DNS server after the primary one. You probably only need this if you&#8217;re running a Windows domain, in which case it should point to the domain controller, or if you have split horizon DNS.</dd>
<dt>wins</dt>
<dd>Tells the client which WINS server to use, for resolving local SMB server names. Again, you probably only need this if you&#8217;re running a Windows domain, in which case it should also point to the domain controller.</dd>
<dt>pool</dt>
<dd>Tells the server which local pool (not DHCP pool) to assign the client&#8217;s address from. You can specify any name here, even a pool that doesn&#8217;t exist, but clients won&#8217;t be able to connect unless the pool name is a valid local pool.</dd>
<dt>acl</dt>
<dd>This ACL, which we defined earlier, is used to tell the clients which subnets are reachable through the connection (split tunnel mode). If no <strong>acl</strong> statement is used, the tunnel is not split, and a default route is set through the VPN tunnel instead.</dd>
<dt>netmask</dt>
<dd>Defines the network mask that the client will apply to its client interface, in combination with the IP address assigned from the pool.</dd>
</dl>
<h3>Profiling</h3>
<p>Next, we create an ISAKMP profile on the server which tells the server to assign IP addresses automatically, and which <a href="http://www.cisco.com/en/US/docs/ios/12_2/dial/configuration/guide/dafvrtmp.html#wp1000958">virtual template</a> to use when creating the virtual-access interfaces for the server side of the tunnel. We haven&#8217;t defined the virtual template yet, but we will in a second.</p>
<pre>
crypto isakmp profile ewb_isakmp_profile
   match identity group EWB
   isakmp authorization list sdm_vpn_group_ml_4
   client configuration address respond
   virtual-template 1
</pre>
<p>When a client connects using the group name <code>EWB</code>, it will check for network authorization using the AAA list name <code>sdm_vpn_group_ml_4</code> (or <code>default</code> if that list doesn&#8217;t exist), respond to IP address requests from the client (using the pool defined in the client configuration above), and create a local virtual-access interface based on virtual template number 1.</p>
<p>You should use the same group name that you used for the <strong>client configuration</strong> above, instead of EWB, unless you&#8217;re EWB of course.</p>
<h3>Strong Encryption</h3>
<p>Now we define the level of encryption used for data communications with hosts on the internal network, as opposed to securing the negotiation process. We start by defining a <em>transform set</em> which uses 256-bit AES encryption, the SHA hash algorithm and LZS compression for data packets:</p>
<pre>
crypto ipsec transform-set ewb_encryption esp-aes 256 esp-sha-hmac comp-lzs
</pre>
<p>Then we create an IPsec profile that links these settings to the ISAKMP profile that we defined above:</p>
<pre>
crypto ipsec profile ewb_ipsec_profile
 set transform-set ewb_encryption
 set isakmp-profile ewb_isakmp_profile
</pre>
<h3>Virtual Template</h3>
<p>Now we define the template for the virtual interfaces, that we referenced above in the ISAKMP policy:</p>
<pre>
interface Virtual-Template1 type tunnel
 ip unnumbered Vlan1
 zone-member security in-zone
 tunnel mode ipsec ipv4
 tunnel protection ipsec profile ewb_ipsec_profile
</pre>
<p>We use <code>ip unnumbered Vlan1</code> to set the IP address of the virtual-access interfaces to the address of the router on the local LAN (in this case it&#8217;s a VLAN bridge), which allows you to ping the router using its internal IP address (192.168.1.1 in our case) when you&#8217;re connected to the VPN, which is a useful connectivity test.</p>
<p>We place the virtual interfaces into the <code>in-zone</code> (internal zone) which means that they have full access to the local network, which is not very secure, but simplifies things. We also specify that this interface accepts only traffic encrypted with IPsec and bound to the profile that we created earlier. I&#8217;m not sure why it needs to be bound in both directions, as the IPsec profile is connected to the ISAKMP profile which is connected to this virtual interface already.</p>
<h3>Client Setup</h3>
<p>That should be it for the server-side setup. To configure a client, install the VPN software you downloaded earlier, start it, create a new IPsec configuration, and enter the following details:</p>
<dl>
<dt>Server</dt>
<dd>The public IP address of the VPN server</dd>
<dt>Group Name</dt>
<dd>The same group name that you used on the server earlier</dd>
<dt>Pre-Shared Key</dt>
<dd>The same key that you entered on the server earlier</dd>
</dl>
<p>Now click on the <strong>Connect</strong> button, and after a few seconds the window should minimize to the system tray, and you should be connected to the VPN. You can check this by pinging the internal IP address of the router (e.g. 192.168.1.1) and if that works, the IP addresses of whatever internal servers you want to connect to.</p>
<p>If it doesn&#8217;t work, use the Log menu to enable logging, try to connect again, and check the results on the Logging tab. You can also try enabling IPsec debugging on the router, in run mode (not configuration mode):</p>
<pre>
debug crypto engine packet
debug crypto ipsec error
debug crypto isakmp error
debug crypto verbose
terminal monitor
</pre>
<p>When the configuration works, write it to the router&#8217;s non-volatile memory to ensure that you don&#8217;t lose it when you next reboot the router:</p>
<pre>
write
</pre>
<p>And that&#8217;s it!</p>
<h3>References</h3>
<p>Here are some random unsorted links to pages that I found useful while figuring out how to do this:</p>
<ul>
<li><a href="http://www.ciskoblog.com/2006/12/configuring-a-c.html">Configuring a Cisco Router to Accept VPN Connections</a> (even simpler example, without split tunnels)</li>
<li><a href="http://www.cisco.com/en/US/docs/ios/sec_secure_connectivity/configuration/guide/sec_key_exch_ipsec.html">Configuring Internet Key Exchange for IPsec VPNs</a> (good general overview of how Cisco&#8217;s IPsec works)</li>
<li><a href="http://www.cisco.com/en/US/docs/ios/sec_secure_connectivity/configuration/guide/sec_easy_vpn_rem.html#wp1060585">Cisco Easy VPN Remote</a> configuration guide</li>
<li><a href="http://samsten.net/work/cvpnc/">Cisco VPN client downloads</a></li>
<li><a href="http://www.ciscocatalyst.info/en/US/docs/ios/ipaddr/command/reference/iad_arp.html#wp1013235">Cisco ARP Commands</a></li>
<li><a href="http://www.cisco.com/en/US/products/ps6017/products_command_reference_chapter09186a00808ab59a.html#wp1016030">Cisco ISAKMP command reference</a></li>
<li><a href="http://www.cisco.com/en/US/docs/routers/access/cisco_router_and_security_device_manager/24/software/user/guide/ZPF.html#wp1020392">Configuring Zone Policy Firewalls</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/08/03/simple-cisco-vpn-how-to/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Network Management Basics</title>
		<link>http://blog.aptivate.org/2010/04/07/network-management-basics/</link>
		<comments>http://blog.aptivate.org/2010/04/07/network-management-basics/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 07:43:20 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Censorship]]></category>
		<category><![CDATA[Education]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[management]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[university]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=419</guid>
		<description><![CDATA[I&#8217;ve been asked for some advice on how schools and universities can take advantage of the increased bandwidth available with the arrival of the TEAMS and EASSY submarine cables in East Africa. Management of Internet connections is a big subject. Whole books have been written about it, including the freely downloadable How To Accelerate Your [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been asked for some advice on how schools and universities can take advantage of the increased bandwidth available with the arrival of the <a href="http://en.wikipedia.org/wiki/TEAMS_(cable_system)">TEAMS</a> and <a href="http://en.wikipedia.org/wiki/EASSy_(cable_system)">EASSY</a> submarine cables in East Africa.</p>
<p>Management of Internet connections is a big subject. Whole books have been written about it, including the freely downloadable <a href="http://bwmo.net">How To Accelerate Your Internet (BMO Book)</a>. However, for anyone who doesn&#8217;t have time to read it, I will briefly summarise the most important points that I can think of:</p>
<ul>
<li>have a clear, simple and strict <a href="http://bwmo.net/pdf/chapter2.pdf">Internet access policy</a>, and enforce<br />
it.</li>
<li>have enough bandwidth, AT LEAST 3 kbps per computer, uncontended. So if you have 1000 computers, you should have 3 MBits dedicated bandwidth, or 60 MBps if it&#8217;s shared or contended with a 20:1 contention ratio (typical ISPs).</li>
<li>have competent network administrators. If you don&#8217;t have them, then hire or train them.</li>
<li>implement good network management practices, e.g. by following the advice of the <a href="http://bwmo.net/">BMO Book</a>.</li>
<li>start by <a href="http://bwmo.net/pdf/chapter5.pdf">solving</a> the problems that users complain most about, to give them the best possible service.</li>
<li><a href="http://bwmo.net/pdf/chapter3.pdf">monitor your network</a> to understand how Internet bandwidth is being used.</li>
<li><a href="http://bwmo.net/pdf/chapter4.pdf">block misuses</a> of Internet access that are causing problems for legitimate use of the Internet connection.</li>
<li>ensure that client PCs have good, fast antivirus, perform well, are<br />
regularly reformatted and reimaged, and have strong local security to prevent unauthorized software installation.</li>
</ul>
<p>Far more information on all of these topics can be found in the BMO book. I suggest starting with the <a href="http://bwmo.net/pdf/chapter1.pdf">Introduction</a> if you&#8217;re interested.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/04/07/network-management-basics/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Writing Database Migrations</title>
		<link>http://blog.aptivate.org/2010/03/30/writing-database-migrations/</link>
		<comments>http://blog.aptivate.org/2010/03/30/writing-database-migrations/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 13:07:37 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rita]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[vcs]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=387</guid>
		<description><![CDATA[Describes how to develop and implement schema and data changes in Java applications backed by SQL databases, using version control and Migrate4J.]]></description>
			<content:encoded><![CDATA[<p>As part of our work on <a href="http://www.logcluster.org/tools/cargo-tracking/rita">RITA</a>, we will need to make schema changes (such as creating tables and adding columns) to live production databases during software upgrades without losing data. Here I will show how <strong>migrations</strong> can be used to implement these changes. Although aimed at <a href="http://migrate4j.sourceforge.net/">Migrate4J</a> users, some of this applies to <a href="http://www.oracle.com/technology/pub/articles/kern-rails-migrations.html">Rails Migrations</a> as well.</p>
<p>We use Migrate4J to implement database migrations in this Java application. This requires us to write Java code to migrate up to, and down from, each specific database version, by making the required database changes: adding tables and fields, changing field names and types, and modifying data.</p>
<p>However, in our team the database designer is not the person writing these migrations. The designer is working on his copy of the database design, keeping in mind backwards compatibility with the <a href="http://www.logcluster.org/tools/cargo-tracking/lctt">LCTT</a> Access database, and giving me Postgres schema dumps. I have to compare these dumps to identify what has changed, and write the migration code.</p>
<h3><a name="comparing">What Changed?</a></h3>
<p>First of all, how does one compare dumps? I found Subversion and Diff to be very helpful. We keep the currently-implemented schema checked into Subversion <a href="http://rita.wfplogistics.org/trac/browser/rita/doc/master-schema-from-aaron.sql">here</a> as a Postgres dump. When I receive a new one, I replace this file, but don&#8217;t immediately check it in. I can use the <code>svn diff</code> command, or the <a href="http://subclipse.tigris.org/">Subclipse</a> plugin&#8217;s Compare With feature, to see all the changes since the last revision.</p>
<p>Unfortunately Postgres dumps contain some lines that change every time and which aren&#8217;t helpful to me, so after I update the dump, I run a command to remove them:</p>
<pre>sed -i.orig -e '/^-- TOC entry/d' -e '/^-- Dependencies:/d' master-schema-from-aaron.sql</pre>
<p>And then show the differences:</p>
<pre>svn diff --diff-cmd=diff -x "-u -F TABLE" master-schema-from-aaron.sql &gt; master-schema-from-aaron.diff</pre>
<p>which produces a file that I can load into a syntax highlighting editor (I often pipe it into <code>less</code> instead), and which looks like this:</p>
<pre>@@ -554,7 +596,7 @@ -- Name: bundle_type_group; Type: TABLE;
 CREATE TABLE bundle_type_group (
     id integer NOT NULL,
     description character varying(255) NOT NULL,
-    is_qty_allowed smallint,
+    is_qty_allowed smallint NOT NULL,
     record_version bigint NOT NULL,
     is_deleted smallint NOT NULL
 );</pre>
<p>This is an extract from a <a href="http://en.wikipedia.org/wiki/Diff#Unified_format">unified diff</a>. The first line, starting with <code>@@</code>, is a header that begins a new section: a block of changed lines, also called a <em>changed hunk</em> or <em>chunk</em>. It includes line numbers from the old and new dump files. It shows three lines of unchanged context above and below the lines that changed.</p>
<p>In this case the line <code>CREATE TABLE bundle_type_group</code> identifies the table being modified, but sometimes the context may not be enough. The last line containing the word <code>TABLE</code> is shown in the header, and normally this helps to identify the table as well.</p>
<p>So this section represents a change to the <code>bundle_type_group</code> table. What changed? A line has been deleted from the dump, and a line has been added. The deleted line is prefixed with <code>-</code> (minus) in the difference file, and the added line is prefixed with <code>+</code> (plus). These lines represent columns in the table.</p>
<p>In this case, the column removed and the column added are both called <code>is_qty_allowed</code>. Because the name is the same, but the types are different, this almost certainly represents a type change to an existing column. If the names were different but the types were the same, it probably represents a renamed column, and if the names and types both differ, it&#8217;s probably a deletion of one column and creation of another, discarding the old contents of the column.</p>
<p>It&#8217;s worth discussing any unclear changes with the database administrator to be sure exactly what needs to be done. Sometimes there will be data-only migration changes that don&#8217;t appear in the schema at all. For example you might decide one day that all people currently called <em>John</em> in the database should now be called <em>Jean</em>, or you might need to add a row to a system table. These can also be done with Migrate4J, but they are not structural (schema) changes.</p>
<h3><a name="migration">Creating a New Migration</a></h3>
<p>Assuming that you already have migrations <a href="http://migrate4j.sourceforge.net/#configuring">configured</a> in your application, you will have a migration package, where all the classes are named Migration_<strong>number</strong>. In our case, the migration package is <a href="http://rita.wfplogistics.org/trac/browser/rita/src/org/wfp/rita/db/migrations">org.wfp.rita.db.migrations</a>. Identify the next migration number in this package, which is usually one higher than the highest <strong>number</strong> present. Create a class in the package with this name, using this template:</p>
<pre>package org.wfp.rita.db.migrations;

/* cleaner sources: */
import static com.eroi.migrate.Execute.*;
import static com.eroi.migrate.Define.*;

public class Migration_2 implements Migration
{
    public void up()
    {
    }

    public void down()
    {
    }
}</pre>
<p>Now you can write code to implement the database changes (both schema and data) that you discovered earlier. Each new change is part of an <strong>upward migration</strong>, and the code that implements it should go into the <code>up</code> method.</p>
<p>It&#8217;s important to be able to reverse changes as well. If a schema update fails, you may want to back down to a previous schema, fix the problem that caused it to fail, and try to update again. The code to reverse the change, which is called a <strong>downward migration</strong>, goes into the <code>down()</code> method.</p>
<p>Note that most migrations lose data in either the forward or the reverse direction (up or down respectively), so you would be well advised to make an automated backup of the database before applying any migrations, in addition to your standard database backup procedures.</p>
<h3><a name="creating">Creating Tables</a></h3>
<p>The <code>Execute.createTable()</code> method takes the table name, and an array of Columns. You can create a new <code>Column</code> with one of these constructors:</p>
<ul>
<li>new Column(String columnName, int columnType)</li>
<li>new Column(String columnName,<br />
int columnType,<br />
int length,<br />
boolean primaryKey,<br />
boolean nullable,<br />
Object defaultValue,<br />
boolean autoincrement)</li>
</ul>
<dl>
<dt>columnType</dt>
<dd>The type of the column, from <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Types.html">java.sql.Types</a>, e.g. Types.INTEGER, Types.FLOAT, Types.VARCHAR.</dd>
<dt>length</dt>
<dd>The length of CHAR and VARCHAR columns. The length of all other column types, particularly DECIMAL, must be specified in another way, see below.</p>
</dd>
<dt>primaryKey</dt>
<dd>True if this column should be part of the primary key, or false otherwise (the default). You can have any number of columns in the primary key, and RITA uses composite primary keys extensively.</dd>
<dt>nullable</dt>
<dd>True if this column should be allowed to contain NULL values, and false otherwise.</dd>
<dt>defaultValue</dt>
<dd>The default value for new rows. If you set this to null, and the column is not nullable, then a value must be supplied for each record inserted.</dd>
<dt>autoincrement</dt>
<dd>True if the column should contain automatically-assigned numbers, using the AUTO_INCREMENT attribute in MySQL, or IDENTITY columns or sequences on databases that support them.</dd>
</dl>
<p>To create a new table called <code>persons</code>, with three columns:</p>
<dl>
<dt><code>ID</code></dt>
<dd>an automatically-assigned integer primary key</dd>
<dt><code>fish</code></dt>
<dd>a float</dd>
<dt><code>rope</code></dt>
<dd>a string, 40 characters long, not nullable, defaulting to <code>nylon</code></dd>
</dl>
<p>we could use the following code in the <code>up</code> migration:</p>
<pre>Execute.createTable(new Table("persons", new Column[]{
    new Column("id", Types.INTEGER, -1, true, false, null, true),
    new Column("fish", Types.FLOAT),
    new Column("rope", Types.VARCHAR, 40, false, false, "nylon", false)
}));</pre>
<p>Unfortunately this syntax doesn&#8217;t allow specifying unique keys, indexes, foreign keys, and precision and scale of decimal columns when the table is created. There is another, shorter syntax which allows specifying the precision and scale:</p>
<pre>createTable(table("persons",
    column("id", INTEGER, notnull(), primarykey()),
    column("fish", NUMERIC, precision(8), scale(5)),
    column("rope", VARCHAR, length(40), notnull(), defaultValue("nylon")),
    ));</pre>
<p>If that still seems like too much work, and you have a database dump of your new schema, have a look at <a href="#generating">generating from Postgres dumps</a> below.</p>
<p>The reverse, which you would normally put into the <code>down()</code> method, is simply to <a href="#dropping">drop the table</a>.</p>
<h3><a name="dropping">Dropping Tables</a></h3>
<p>Dropping a table is as simple as:</p>
<pre>Execute.dropTable("persons");</pre>
<p>Note that all data in the table will be lost. To recreate the empty table structure in the reverse migration, just <a href="#creating">create it again</a>.</p>
<h3><a name="adding">Adding Columns</a></h3>
<p>To add an <code>INTEGER</code> column called <code>hairs</code> to the <code>persons</code> table, you would add the following code to the <code>up()</code> method:</p>
<pre>Execute.addColumn(new Column("hairs", Types.INTEGER), "persons");</pre>
<p>The addColumn method takes a <code>Column</code> object, which you can create using either of the methods <code>new Column(...)</code> or <code>column(...)</code> described under <a href="#creating">creating tables</a> above. The <code>column(...)</code> method is shorter, and the only way to specify the scale and precision of decimal (NUMERIC) columns.</p>
<p>If the change is adding a column, the reverse is to remove the column again, which belongs in the <code>down()</code> method:</p>
<pre>Execute.dropColumn("hairs", "persons");</pre>
<p>Note that your newly added column will contain default values for all records. If you know what the values should be, or can recreate them using a query, you could <a href="queries">execute SQL queries</a> to populate it. Also note that if you migrate down past this version, the column will be dropped and all data contained in it will be lost.</p>
<h3><a name="removing">Removing Columns</a></h3>
<p>This is the exact opposite of <a href="#adding">Adding Columns</a> above. Put the <code>dropColumn()</code> in the <code>up</code> migration, and the <code>addColumn()</code> in the <code>down</code> migration.</p>
<p>Note that migrating down past this migration will not restore the data that was in your column before. If you know what it was, or can recreate it using a query, you could reinsert it using <a href="queries">SQL queries</a>.</p>
<h3><a name="renaming">Renaming Columns</a></h3>
<p>Changing the name of a column does not lose any data. For example, we can rename the column called <code>fish</code> to <code>hats</code> in the <code>persons</code> table, and hope that people don&#8217;t try to wear their pet haddock:</p>
<pre>Execute.renameColumn("fish", "hats", "persons");</pre>
<p>The <code>down()</code> migration trivially renames the column from the new name back to the old name.</p>
<h3><a name="indexes">Indexes</a></h3>
<p>You can add indexes to columns, both to improve search performance, and to enforce the uniqueness of values in certain columns. The <code>addIndex()</code> method takes an <code>Index</code> object, which you can either create by calling its constructor, or more concisely by calling <code>index()</code> or <code>uniqueIndex()</code>. Both take the same parameters:</p>
<pre>index(String indexName, String tableName, String... columnNames)</pre>
<p><code>indexName</code> is the name of the index, which can be <code>null</code> to generate a name automatically. However, such indexes cannot reliably be removed, so I recommend always naming your indexes explicitly. <code>tableName</code> is the name of the table that the index will be applied to, and <code>columnNames</code> is a list of names of columns that will be included in the index.</p>
<p>For example, to uniquely index the <code>fish</code> and <code>rope</code> columns in the <code>persons</code> table:</p>
<pre>Execute.addIndex(uniqueIndex("uk_fish_rope", "persons", "fish", "rope"));</pre>
<p>You can drop an index, for example for downward migration, using the index name and the table name:</p>
<pre>Execute.dropIndex("uk_fish_rope", "persons");</pre>
<h3><a name="foreign_keys">Foreign Keys</a></h3>
<p>Foreign keys link one table to another, to enforce referential integrity between tables. You can create them with <code>Execute.addForeignKey()</code>, which takes a <code>ForeignKey</code> object. There are four ways to construct a ForeignKey:</p>
<ul>
<li>ForeignKey(String name, String parentTable, String <strong>parentColumn</strong>, String childTable, String <strong>childColumn</strong>)</li>
<li>ForeignKey(String name, String parentTable, String parentColumn, String childTable, String childColumn, <strong>CascadeRule deleteRule, CascadeRule updateRule</strong>)</li>
<li>ForeignKey(String name, String parentTable, String[] <strong>parentColumns</strong>, String childTable, String[] <strong>childColumns</strong>)</li>
<li>ForeignKey(String name, String parentTable, String[] parentColumns, String childTable, String[] childColumns, <strong>CascadeRule cascadeDeleteRule, CascadeRule cascadeUpdateRule</strong>)</li>
</ul>
<p>As you can see, these are just the four combinations of whether parentColumns and childColumns are single column names or arrays of column names, and whether the cascade rules are specified or not (they default to &#8220;none&#8221; if not supplied).</p>
<p>For example, to force a person&#8217;s <code>fish_id</code> column to point to the ID of a record in the <code>fish</code> table, you could use this:</p>
<pre>Execute.addForeignKey(new ForeignKey("fk_persons_fish", "persons", "fish_id", "fish", "id"));</pre>
<p>You can drop a foreign key, for example for downward migration, using the key name and the child (referenced) table name:</p>
<pre>Execute.dropIndex("fk_persons_fish", "fish");</pre>
<h3><a name="queries">Executing Queries</a></h3>
<p>You can execute any arbitrary SQL statement, for example to insert rows into a newly created table or populate a newly created column:</p>
<pre>Execute.executeStatement(Configure.getConnection(),
    "INSERT INTO users SET name = 'fred', password = 'flintstone'");
Execute.executeStatement(Configure.getConnection(),
    "UPDATE users SET age = 42 WHERE name = 'barney'");</pre>
<p>Although data modification language is much more standard across databases than data definition language, it&#8217;s important to be careful only to use ANSI SQL in such statements if cross-database compatibility is important for your application (or might become important in future).</p>
<h3><a name="generating">Generating Automatically</a></h3>
<p>If you already have a table structure in a database somewhere, for example if you are retrofitting migrations to an existing project, or if you prefer using GUI tools to design databases, and to reduce the risk of errors, you may want to generate the migration code automatically.</p>
<p>I wrote a <a href="http://rita.wfplogistics.org/trac/browser/rita/tools/generate-migration-from-postgres-dump.pl">script</a> to create Migrate4J migrations automatically from Postgres database dumps. It&#8217;s not perfect, it probably only handles the SQL that we actually use, and it&#8217;s not well tested, but it may help you. Just run it with the name of the exported schema dump file as its parameter, and it will generate Java code on the standard output, that you can copy and paste into a Java source file.</p>
<p>If the schema will continue to change, and you want help with creating new table definitions in future, you can save the <a href="http://rita.wfplogistics.org/trac/browser/rita/doc/master-schema-from-aaron.migrate">generated output</a> to a file under version control. When you need to generate migration code for a new schema, just overwrite that file, and use <code>svn diff</code> as before to show the differences. They will now be expressed in Java code, which is easier to copy and paste into a new migration.</p>
<h3><a name="generating">Applying Manually</a></h3>
<p>In Eclipse, with a <code>migrate4j.properties</code> file on your classpath, you should be able to open the Migrate4J JAR file in Eclipse, expand the <code>com.eroi.migrate</code> package, right-click on <code>Engine</code> and choose &#8220;Run As/Java Application&#8221;.</p>
<h3><a name="generating">Applying Programmatically</a></h3>
<p>As we are using Hibernate, we get a database connection using its Work class, and use it to invoke the migration engine:</p>
<pre>
// set up Migration schema and run all migrations
m_Session.doWork(new Work()
{
    public void execute(Connection connection) throws SQLException
    {
        Configure.configure(connection, "org.wfp.rita.db.migrations");
        Engine.migrate();
    }
});
</pre>
<h3><a name="controlling">Version Control</a></h3>
<p>If I don&#8217;t check in the master schema changes immediately, when does it happen? I try to wait until I have all the schema changes implemented in Hibernate annotations and migrations, and run as many tests as I feel the need to run, before checking everything in.</p>
<p>This ensures that the documentation checked in is consistent with the code at that point in time, that I can see the changes to the SQL dump, the Hibernate mappings and the migrations for a single schema update and compare them side-by-side, and reduces the risk of checking in broken code.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2010/03/30/writing-database-migrations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

