<?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>Adrian Smith&#039;s Blog &#187; howto</title>
	<atom:link href="http://www.17od.com/tag/howto/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.17od.com</link>
	<description></description>
	<lastBuildDate>Sun, 20 Nov 2011 20:04:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>How to Create a Remote Paging Listview Using GWT-Ext</title>
		<link>http://www.17od.com/2008/07/24/how-to-create-a-remote-paging-listview-using-gwt-ext/</link>
		<comments>http://www.17od.com/2008/07/24/how-to-create-a-remote-paging-listview-using-gwt-ext/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 18:05:36 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=73</guid>
		<description><![CDATA[Creating a remote paging listview isn&#8217;t particularly difficult but getting to the point of knowing how all the pieces fit together can be tricky first time round. This post describes how I created a very simple remote paging listview that retrieves each page of data from an Oracle database table. As well as describing the [...]]]></description>
			<content:encoded><![CDATA[<p>Creating a remote paging listview isn&#8217;t particularly difficult but getting to the point of knowing how all the pieces fit together can be tricky first time round. This post describes how I created a very simple remote paging listview that retrieves each page of data from an Oracle database table. As well as describing the listview I&#8217;ve also included the code for the server side that actually fetches and returns each page of data to the client.</p>
<p><strong>Deploying GWT-Ext</strong><br />
If you&#8217;ve not used <a href="http://www.gwt-ext.com/">GWT-Ext</a> before then here&#8217;s how to include it in your GWT application. First you&#8217;ll need to download GWT-Ext itself. At the time of writing 2.0.4 is the latest release, you can get it <a href="http://code.google.com/p/gwt-ext/downloads/list">here</a>. The real workhorse behind GWT-Ext is the Javascript library <a href="http://extjs.com/">ExtJS</a>. GWT-Ext 2.0.4 requires ExtJS 2.0.2 which you can download from <a href="http://yogurtearl.com/ext-2.0.2.zip">here</a>.</p>
<p>If you don&#8217;t already have a GWT application then GWT&#8217;s <a href="http://code.google.com/docreader/#p(google-web-toolkit-doc-1-5)s(google-web-toolkit-doc-1-5)t(GettingStartedBasics)">The Basics</a> guide is a good place to start.</p>
<p>With your application up and running here are the steps required to deploy GWT-Ext within it.</p>
<p>1. Create the directory <code>js/ext</code> under your application&#8217;s <code>public</code> folder and copy the following files and directories from ExtJS into it,</p>
<pre><code>adapter
resources
ext-all.js
ext-all-debug.js
ext-core.js
ext-core-debug.js</code></pre>
<p>2. Edit your module file and add these lines to it,</p>
<pre><code>&lt;inherits name='com.gwtext.GwtExt'/&gt;
&lt;stylesheet src="js/ext/resources/css/ext-all.css"/&gt;
&lt;script src="js/ext/adapter/ext/ext-base.js" /&gt;
&lt;script src="js/ext/ext-all.js" /&gt;</code></pre>
<p>3. The final step it to add the GWT-Ext jar, gwtext.jar, to your application&#8217;s classpath.</p>
<p><strong>The Client Side Code</strong><br />
GWT-Ext refers to a listview as a Grid so to avoid confusion I&#8217;ll use that term throughout the rest of this post. I used the term listview up to this point because it&#8217;s probably a more generally accepted description.</p>
<p>Before going into the code it&#8217;s worth spending a little time understanding the various objects that are needed to support the Grid object. The first thing worth pointing out is that GWT-Ext doesn&#8217;t use standard <a href="http://code.google.com/docreader/#p(google-web-toolkit-doc-1-5)s(google-web-toolkit-doc-1-5)t(DevGuideRemoteProcedureCalls)">GWT Remote Procedure Calls</a> to fetch the data needed in the Grid. What you do instead is provide it with a HTTP URL from which to retrieve the data. To do this you use a <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/DataProxy.html">DataProxy</a> object. There are three types of DataProxy, the <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/HttpProxy.html">HttpProxy</a>, the <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/MemoryProxy.html">MemoryProxy</a> and the <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/ScriptTagProxy.html">ScriptTagProxy</a>. The MemoryProxy is just a static in memory data source and the ScriptTagProxy is the same as HttpProxy except that it retrieves data from a site other than the one where your Grid is hosted. So what format should the data coming back from this URL be in? Two formats are supported, JSON and XML. In order to understand the structure of this JSON or XML we need to use a <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/RecordDef.html">RecordDef</a>. This object contains <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/FieldDef.html">FieldDef</a> objects each of which describe a particular field in the data feed. Once you&#8217;ve described you data structure using a RecordDef you create either a <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/JsonReader.html">JsonReader</a> or an <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/XmlReader.html">XmlReader</a> and give it a reference to your RecordDef. Finally, to tie all these objects together you create a <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/data/Store.html">Store</a>. The Store is the object you present to the Grid. It uses the DataProxy to retrieve the data and and the Reader to parse it.</p>
<p>With the Store defined we can turn our attention to the Grid. To define what columns the Grid should have and where the data for each column should come from we use a <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/widgets/grid/ColumnModel.html">ColumnModel</a> object. This object contains a number of <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/widgets/grid/ColumnConfig.html">ColumnConfig</a> objects, one for each column. A ColumnConfig contains the column title, the name of the record in the RecordDef to populate the column with, it&#8217;s width, weather it&#8217;s sortable and how the data should be rendered. To create the Grid itself we use the <a href="http://gwt-ext.com/docs/2.0.4/com/gwtext/client/widgets/grid/GridPanel.html">GridPanel</a> object. You can link it to the Store and ColumnModel using either the constructor or the setter methods.</p>
<p>The final point to note is that you&#8217;ll need to add an <strong>onRender</strong> event handler to the Grid so that the first page of data is loaded when the Grid is displayed.</p>
<p>Bringing all that together here&#8217;s the class I ended up with,</p>
<pre></code>package com._17od.gwtexamples.client;

import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.gwtext.client.core.SortDir;
import com.gwtext.client.data.DateFieldDef;
import com.gwtext.client.data.FieldDef;
import com.gwtext.client.data.HttpProxy;
import com.gwtext.client.data.IntegerFieldDef;
import com.gwtext.client.data.JsonReader;
import com.gwtext.client.data.Record;
import com.gwtext.client.data.RecordDef;
import com.gwtext.client.data.Store;
import com.gwtext.client.data.StringFieldDef;
import com.gwtext.client.util.DateUtil;
import com.gwtext.client.widgets.Component;
import com.gwtext.client.widgets.PagingToolbar;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.event.PanelListenerAdapter;
import com.gwtext.client.widgets.grid.CellMetadata;
import com.gwtext.client.widgets.grid.ColumnConfig;
import com.gwtext.client.widgets.grid.ColumnModel;
import com.gwtext.client.widgets.grid.GridPanel;
import com.gwtext.client.widgets.grid.GridView;
import com.gwtext.client.widgets.grid.Renderer;
import com.gwtext.client.widgets.grid.RowSelectionModel;

public class PersonGrid implements EntryPoint {

	public void onModuleLoad() {

		Panel panel = new Panel();
		panel.setBorder(false);
		panel.setPaddings(15);

		HttpProxy dataProxy = new HttpProxy("http://localhost:8888/persons");

        final RecordDef recordDef = new RecordDef(new FieldDef[]{
                new StringFieldDef("class"),
                new DateFieldDef("dateOfBirth", "Y-m-d"),
                new StringFieldDef("firstname"),
                new IntegerFieldDef("id"),
                new StringFieldDef("lastname"),
        });

        JsonReader reader = new JsonReader(recordDef);
        reader.setRoot("persons");
        reader.setTotalProperty("totalPerons");
        reader.setId("id");

        final Store store = new Store(dataProxy, reader, true);
        store.setDefaultSort("id", SortDir.ASC);

        ColumnConfig firstNameColumn = new ColumnConfig("First Name", "firstname", 45, true);
        ColumnConfig lastNameColumn = new ColumnConfig("Last Name", "lastname", 45, true);
        ColumnConfig dateOfBirthColumn = new ColumnConfig("Date of Birth", "dateOfBirth", 45, true, dateRender);

        ColumnModel columnModel = new ColumnModel(new ColumnConfig[] {
        		firstNameColumn,
        		lastNameColumn,
        		dateOfBirthColumn});
        columnModel.setDefaultSortable(true);

        GridPanel grid = new GridPanel();
        grid.setWidth(700);
        grid.setHeight(300);
        grid.setTitle("People");
        grid.setStore(store);
        grid.setColumnModel(columnModel);
        grid.setTrackMouseOver(true);
        grid.setLoadMask(true);
        grid.setSelectionModel(new RowSelectionModel());
        grid.setStripeRows(true);
        grid.setIconCls("grid-icon");
        grid.setEnableColumnResize(true);

        GridView view = new GridView();
        view.setForceFit(true);
        grid.setView(view);

        PagingToolbar pagingToolbar = new PagingToolbar(store);
        pagingToolbar.setPageSize(15);
        pagingToolbar.setDisplayInfo(true);

        grid.setBottomToolbar(pagingToolbar);

        grid.addListener(new PanelListenerAdapter() {
            public void onRender(Component component) {
                store.load(0, 15);
            }
        });
        panel.add(grid);

        RootPanel.get().add(panel);

  	}

    private Renderer dateRender = new Renderer() {
        public String render(Object value, CellMetadata cellMetadata, Record record, int rowIndex, int colNum, Store store) {
            return DateUtil.format((Date) value, "d-m-Y");
        }
    };

}</code></pre>
<p><strong>Where Does the Data Come From?</strong><br />
The code below is the servlet I developed to return each page of data to the Grid. It retrieves the data from an Oracle database table called “person”. It&#8217;s not particularly complicated but it does demonstrate some challenges that are worth pointing out.</p>
<pre></code>package com._17od.gwtexamples.servlets;

import java.io.IOException;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import oracle.jdbc.pool.OracleDataSource;

import org.json.JSONArray;
import org.json.JSONObject;

public class GetPersonsServlet extends HttpServlet {

	private Connection connection;

	public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
		doPost(req, res);
	}

	public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {

		// Display the parameters we're passed in for debugging purposes
		printParameters(req);

		// Get the limit and sort parameters off the request
		int start = req.getParameter("start") == null ? 1 : Integer.parseInt(req.getParameter("start"));
		int numberToReturn = req.getParameter("limit") == null ? 10 : Integer.parseInt(req.getParameter("limit"));
		String sortBy = req.getParameter("sort") == null ? "id" : req.getParameter("sort");
		String sortOrder = req.getParameter("dir") == null ? "asc" : req.getParameter("dir");

		// Create the SQL query used to retrieve the persons
		String sql = createMainSQLQuery(sortBy, sortOrder);

		ArrayList persons = null;
		try {

			// Get a connection to the Oracle database and put it on the object so that it's easily accessible
			connection = getConnection();

			// Execute the query to return the exact records requested
			persons = queryForPersonsUsingLimits(sql, start, numberToReturn);

			// Convert the list of persons into a JSON string
			JSONObject jsonDataToReturn = new JSONObject();
			JSONArray jsonPersons = new JSONArray(persons, true);
			jsonDataToReturn.put("totalPerons", getTotalNumberOfPersons(sql));
			jsonDataToReturn.put("persons", jsonPersons);

			// Write everything back to the requestor
			res.getWriter().print(jsonDataToReturn.toString(1));

		} catch (Exception e) {
			e.printStackTrace();
			throw new IOException(e);
		} finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					e.printStackTrace();
					throw new IOException(e);
				}
			}
		}

	}

	/**
	 * Create the query used to retrieve the persons from the database.
	 * @param sortBy
	 * @param sortOrder
	 * @return
	 */
	private String createMainSQLQuery(String sortBy, String sortOrder) {

		StringBuffer sql = new StringBuffer("SELECT id, firstname, lastname, dateofbirth FROM person");
		sql.append(" ORDER BY ");
		sql.append(sortBy);
		sql.append(" ");
		sql.append(sortOrder);

		return sql.toString();

	}

	/**
	 * Wrap the query passed in with some extra SQL that pulls out the exact
	 * page of persons requested, i.e. starting at record number 10 return 20
	 * records.
	 * It's vital that the query given in 'sql' has an 'order by' clause.
	 * If it didn't then the persons could be returned in a random order
	 * making it impossible to order them into pages.
	 * @param sql
	 * @param start
	 * @param numberToReturn
	 * @return
	 * @throws SQLException
	 */
	private ArrayList queryForPersonsUsingLimits(String sql, int start, int numberToReturn) throws SQLException {

		StringBuffer sqlBuffer = new StringBuffer("SELECT * FROM (SELECT a.*, ROWNUM rnum from (");
		sqlBuffer.append(sql);
		sqlBuffer.append(") a WHERE ROWNUM <= ");
		sqlBuffer.append(start + numberToReturn);
		sqlBuffer.append(") WHERE rnum > ");
		sqlBuffer.append(start);

		Statement statement = null;
		ResultSet rs = null;

		ArrayList
<person> persons = new ArrayList
<person>();

		try {

			statement = connection.createStatement();
			rs = statement.executeQuery(sqlBuffer.toString());

			while (rs.next()) {
				Person person = new Person();
				person.setId(rs.getInt("id"));
				person.setFirstname(rs.getString("firstname"));
				person.setLastname(rs.getString("lastname"));
				person.setDateOfBirth(rs.getDate("dateofbirth"));
				persons.add(person);
			}

		} finally {
			if (rs != null) {
				rs.close();
			}
			if (statement != null) {
				statement.close();
			}
		}

		return persons;

	}

	/**
	 * Return the total numbner of records that the given query will return.
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	private int getTotalNumberOfPersons(String sql) throws SQLException {

		int count = 0;

		StringBuffer sqlBuffer = new StringBuffer("SELECT COUNT(*) count FROM (");
		sqlBuffer.append(sql);
		sqlBuffer.append(")");

		Statement statement = null;
		ResultSet rs = null;

		try {

			statement = connection.createStatement();
			rs = statement.executeQuery(sqlBuffer.toString());

			while (rs.next()) {
				count = rs.getInt("count");
			}

		} finally {
			if (rs != null) {
				rs.close();
			}
			if (statement != null) {
				statement.close();
			}
		}

		return count;

	}

	/**
	 * Return a database connection from the connection poll that's stored on the servlet/application context
	 * @return
	 * @throws SQLException
	 */
	private Connection getConnection() throws SQLException {
		OracleDataSource ods = (OracleDataSource) getServletContext().getAttribute("CONNECTION_POOL");
		if (ods == null) {
			ods = createConnectionPool();
			getServletContext().setAttribute("CONNECTION_POOL", ods);
		}
		return ods.getConnection();
	}

	/**
	 * Create a database connection pool
	 * @return
	 * @throws SQLException
	 */
	private OracleDataSource createConnectionPool() throws SQLException {
        String username = "replace with db username";
        String password = "replace with db password";
        String url = "jdbc:oracle:thin:@localhost:1521:XE";

        OracleDataSource ods = new OracleDataSource();
        ods.setURL(url);
        ods.setUser(username);
        ods.setPassword(password);
        ods.setConnectionCachingEnabled(true);

        return ods;
	}

	private void printParameters(HttpServletRequest req) {
		Enumeration parameterNames = req.getParameterNames();
		System.out.println("\nRequest Parameters:");
		while (parameterNames.hasMoreElements()) {
			String parameterName = (String) parameterNames.nextElement();
			System.out.println(" " + parameterName + "=" + req.getParameter(parameterName));
		}
	}

}</code></pre>
<p>The first point of interest in doPost() is the code that takes the ordering and limit parameters off the request. This servlet is requested when the grid is first drawn or when the user clicks on the “Next Page” or “Previous Page” buttons. For the paging to work the data needs to be ordered. The <strong>sort</strong> parameter indicates what column to sort the data by. It uses the name you give the column in the RecordDef when creating the Grid. The <strong>dir</strong> parameter says what direction the ordering should be in, ascending or descending. The <strong>start</strong> parameter is the number of the first record to return and <strong>limit</strong> is the number of records to return.</p>
<p>Now that we know what the user is asking for it&#8217;s time to build the SQL query that will fetch that data. The method createMainSQLQuery() creates a query string to select the required columns and order the ResultSet.</p>
<p>In the next section we call getConnection(). This method (and createConnectionPool()) demonstrate how to create an Oracle connection pool using OracleDataSource and it&#8217;s method setConnectionCachingEnabled().</p>
<p>The method queryForPersonsUsingLimits() is where we actually execute the query. In the first section the query is wrapped in some SQL that fetches only the rows we want starting at row start and returning only numberToReturn records. I picked this up from <a href="http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html">this Ask Tom article</a>. It&#8217;s well worth a read if you&#8217;re interested in how the ROWNUM pseudocolumn works.</p>
<p>The next section takes the query ResultSet, creates a Person object for each row and puts each on an ArrayList.</p>
<p>Back in doPost() the ArrayList of Persons is serialized to JSON text using the JSON classes freely availabe <a href="http://www.json.org/java/index.html">here</a>. The method getTotalNumberOfPersons() is called to retrieve the total number of rows the query would return if we weren&#8217;t limiting the results. The reason we need this is because the Grid will have a message at the bottom saying like “Displaying 1 to 20 of 100”. The  getTotalNumberOfPersons() method reuses the SQL we created earlier and simply wraps it in a SELECT COUNT(*).</p>
<p>Finally we write the JSON text to the output stream which is sent back to the browser.</p>
<p>Deploying the servlet into a web application is simply a matter of adding <strong>servlet</strong> and <strong>servlet-mapping</strong> entries to the application&#8217;s web.xml. For testing purposed I chose to use the web application created by GWT. By default this application is located in the <strong>&lt;project dir&gt;\tomcat\webapps\ROOT</strong>. Here are the entries I added&#8230;</p>
<pre></code>&lt;servlet&gt;
    &lt;servlet-name&gt;GetPersonsServlet&lt;/servlet-name&gt;
    &lt;servlet-class&gt;com._17od.GetPersonsServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;

&lt;servlet-mapping&gt;
    &lt;servlet-name&gt;GetPersonsServlet&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/persons&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</code></pre>
<p>Here&#8217;s a sample of the JSON returned from the URL http://localhost:8888/persons?start=2&#038;limit=3.</p>
<pre><code>{
 "persons": [
  {
   "class": "class com._17od.servlets.Person",
   "dateOfBirth": "1901-01-17",
   "firstname": "Laurel",
   "id": 3,
   "lastname": "Davis"
  },
  {
   "class": "class com._17od.servlets.Person",
   "dateOfBirth": "1892-05-16",
   "firstname": "Ted",
   "id": 4,
   "lastname": "Schoenberger"
  },
  {
   "class": "class com._17od.servlets.Person",
   "dateOfBirth": "2001-05-19",
   "firstname": "Rebecca",
   "id": 5,
   "lastname": "Taylor"
  }
 ],
 "totalPerons": 20
}</code></pre>
<p>The JSON implementation I&#8217;m using includes the name of the class being serialized, hence the class attribute.</p>
<p>Since I&#8217;ve included all the other code here&#8217;s the Person class,</p>
<pre></code>package com._17od.gwtexamples.servlets;

import java.util.Date;

public class Person {

	private int id;
	private String firstname;
	private String lastname;
	private Date dateOfBirth;

	public Date getDateOfBirth() {
		return dateOfBirth;
	}

	public void setDateOfBirth(Date dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public int getId() {
		return id;
	}

	public void setId(int personId) {
		this.id = personId;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;

	}

}</code></pre>
<p>To finish off here&#8217;s a screenshot of the Grid,<br />
<a href="http://localhost/17od/wp-content/uploads/2008/07/screenshot-persongrid.png"><img src="http://localhost/17od/wp-content/uploads/2008/07/screenshot-persongrid.png" alt="Grid Screenshot" title="screenshot-persongrid" width="500" height="226" class="size-full wp-image-90" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2008/07/24/how-to-create-a-remote-paging-listview-using-gwt-ext/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Installing Mercurial with Apache</title>
		<link>http://www.17od.com/2008/04/02/installing-mercurial-with-apache/</link>
		<comments>http://www.17od.com/2008/04/02/installing-mercurial-with-apache/#comments</comments>
		<pubDate>Wed, 02 Apr 2008 18:34:14 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=71</guid>
		<description><![CDATA[If you&#8217;ve been following one of these guides explaining how to configure Mercurial with Apache you may have encountered the following error&#8230; TypeError: 'hgwebdir' object is not callable There may be a number of scenarios under which this error can happen but in my case it was because I was using an incompatible version hgwebdir.cgi. [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve been following <a href="http://www.selenic.com/mercurial/wiki/index.cgi/PublishingRepositories">one</a> of <a href="http://www.selenic.com/mercurial/wiki/index.cgi/HgWebDirStepByStep">these</a> <a href="http://digitalspaghetti.me.uk/2007/11/setting-up-a-mercurial-repository-from-svn-for-dummies-like-me/">guides</a> explaining how to configure Mercurial with Apache you may have encountered the following error&#8230;</p>
<pre><code>TypeError: 'hgwebdir' object is not callable</code></pre>
<p>There may be a number of scenarios under which this error can happen but in my case it was because I was using an incompatible version hgwebdir.cgi. After installing Mercurial 0.9.4 I downloaded hgwebdir.cgi from <a href="http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi">here</a> (which at the time of writing was for Mercurial 1.0). To fix the problem I had to use the version of hgwebdir.cgi that came with the Mercurial 0.9.4 install. On Ubuntu you&#8217;ll find it here /usr/share/doc/mercurial/examples/hgwebdir.cgi.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2008/04/02/installing-mercurial-with-apache/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Accessing the NIB &amp; ROS Websites Using Linux</title>
		<link>http://www.17od.com/2007/11/04/accessing-the-nib-ros-websites-using-linux/</link>
		<comments>http://www.17od.com/2007/11/04/accessing-the-nib-ros-websites-using-linux/#comments</comments>
		<pubDate>Sun, 04 Nov 2007 17:49:27 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[banking]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[irish]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[ros]]></category>

		<guid isPermaLink="false">http://www.17od.com/2007/11/04/accessing-the-nib-ros-websites-using-linux/</guid>
		<description><![CDATA[Flexible and all as the Linux operating system is there are a few drawbacks that make the experience less than perfect. One of the main reasons I didn&#8217;t go Linux 100% of the time was that there was always one or two applications that I couldn&#8217;t live without that only ran on Windows. The main [...]]]></description>
			<content:encoded><![CDATA[<p>Flexible and all as the Linux operating system is there are a few drawbacks that make the experience less than perfect. One of the main reasons I didn&#8217;t go Linux 100% of the time was that there was always one or two applications that I couldn&#8217;t live without that only ran on Windows. The main one was Internet Explorer, or more specifically a few websites that I use that were designed to only work with Internet Explorer. The websites in question are my bank&#8217;s, <a href="https://ebanking.nationalirishbank.ie">NIB</a> and the Irish revenue website <a href="http://www.ros.ie">ROS</a>. In fairness to NIB they do offer a workaround but it involves using an a calculator like device to generate a unique token each time you logon to their website.</p>
<p>As it happens, getting Internet Explorer to work in Linux is relatively straightforward. The tricky bit it pulling the various pieces of the puzzle together.</p>
<p><strong>Install Wine and Internet Explorer</strong><br />
Because the problem of not having access to IE within Linux is such a common problem, some nice people have put together an install process that installs both Wine and IE with minimal fuss. It&#8217;s called <a href="http://www.tatanka.com.br/">IEs4Linux</a>. To make the process as painless as possible there&#8217;s a step by step guide available <a href="http://www.howtoforge.com/ubuntu_internet_explorer">here</a>. The most important thing to remember is to carry out the install as a normal user, i.e. NOT the root user.</p>
<p>If you&#8217;re running Ubuntu Gutsy then for step 2 add the following lines to <code>/etc/apt/sources.list</code></p>
<pre><code>deb http://de.archive.ubuntu.com/ubuntu gutsy universe
deb http://wine.budgetdedicated.com/apt gutsy main</code></pre>
<p>When asked if I wanted to install IE5.5 or IE5.0 I said no. That meant that only IE 6 was installed. Installing all three isn&#8217;t a problem but I had no need for 5.0 and 5.5.</p>
<p>Once the process has finished you should have an Internet Explorer icon on your desktop.</p>
<p><strong>Installing the Java Runtime Environment Plug-in for IE</strong><br />
This was the part that I was a little unsure about. I thought getting IE to run was an achievement but I never thought the IE JRE plug-in would work. As luck would have it I came across <a href="http://rmathew.blogspot.com/2007/04/running-java-applets-in-internet.html">this post</a> by Ranjit Mathew that was exactly what I needed.</p>
<p>Following Ranjit&#8217;s post here are the steps I carried out&#8230;</p>
<p>i) Go to the Sun website and download the latest version of the Windows 1.5 JRE. The reason for using 1.5 and not the latest 1.6 is that the <a href="http://www.ros.ie/PublisherServlet/requirements">ROS website</a> states that they only support Sun 1.5 on IE6. The 1.6 version may work but I didn&#8217;t want to tempt faith.</p>
<p>ii) Open a command prompt and execute the following lines,</p>
<pre><code>export WINEPREFIX=$HOME/.ies4linux/ie6
wine jre-1_5_0_13-windows-i586-p.exe</code></pre>
<p>iii) I was having some problems with the entire screen blacking out when I&#8217;d visit a page with a Java applet on it. If you have the same problem open a command prompt and execute these commands&#8230;</p>
<pre><code>export WINEPREFIX=$HOME/.ies4linux/ie6
regedit</code></pre>
<p>Go to the key HKEY_CURRENT_USER\Software\JavaSoft\Java2D\1.5.0_13 and set the property &#8220;DXAcceleration&#8221; to 0.</p>
<p><strong>Installing The ROS Software</strong><br />
When you visit the ROS website for the first time you&#8217;ll have to install the KCrypto software. KCrypto is the Java code that handles the secure transfer of data between your browser and the NIB servers. The first time I tried to install it it failed. The second time it worked fine.</p>
<p><strong>Installing your ROS Certificates</strong><br />
Your ROS security certificates are held in the folder <code>C:\ROS</code> on your Windows machine. Copy this entire folder from your Windows machine into the folder <code>$HOME/.ies4linux/ie6/drive_c</code>. When you restart your IE browser you should see your user id appear on the ROS logon page.</p>
<p><strong>Installing you NIB UserID File</strong><br />
i) Logon to your NIB account on your Windows machine<br />
ii) Click on &#8220;Settings&#8221; at the top of the page and then &#8220;Security&#8221; in the left hand menu<br />
iii) Select the function &#8220;Back up user ID&#8221; and click OK<br />
iv) On the next screen click OK. Take the file that&#8217;s downloaded and go back to your Linux machine<br />
v) Start up IE and go to the logon page<br />
vi) Select &#8220;Search for user id&#8221; just under the userid and password fields. Browse to where you have the file downloaded in step iv, select the second radio button (i.e. copy to a local location) and click OK</p>
<p>That&#8217;s it. One step closer to going Linux full time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2007/11/04/accessing-the-nib-ros-websites-using-linux/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Installing Mythbuntu 7.10</title>
		<link>http://www.17od.com/2007/10/26/installing-mythbuntu-710/</link>
		<comments>http://www.17od.com/2007/10/26/installing-mythbuntu-710/#comments</comments>
		<pubDate>Fri, 26 Oct 2007 22:52:43 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mythtv]]></category>

		<guid isPermaLink="false">http://www.17od.com/2007/10/26/installing-mythbuntu-710/</guid>
		<description><![CDATA[Mythbuntu is &#8220;an Ubuntu derivative focused upon setting up a standalone MythTV system similar to Knoppmyth or Mythdora&#8221;. The last time I installed MythTV I did it on a standard Ubuntu desktop installation. The problem with this is that as well as ending up with a load of software you don&#8217;t really need you have [...]]]></description>
			<content:encoded><![CDATA[<p>Mythbuntu is &#8220;an Ubuntu derivative focused upon setting up a standalone MythTV system similar to Knoppmyth or Mythdora&#8221;. The last time I installed MythTV I did it on a standard Ubuntu desktop installation. The problem with this is that as well as ending up with a load of software you don&#8217;t really need you have to go through the pain of installing and configuring your TV card, graphics card, remote control and so on. Mythbuntu on the other hand takes care of absolutely everything. I won&#8217;t go into the details of the installation (because it&#8217;s pretty much next, next, next&#8230;) but suffice to say, Mythbuntu makes the whole process extremely simple. There were just two areas I had problems with, configuring XMLTV and configuring my wireless card.</p>
<p>The last time I installed MythTV I had the same problem with XMLTV. I don&#8217;t know if it&#8217;s something that I keep missing but after the installation <code>mythfilldatabase</code> never seems to works properly. The problem is that the XMLTV file containing the list of channels to fetch program information for never gets created. Luckily it&#8217;s easy enough to fix. What you do is take the name of the Video Source you setup in the MythTV Backend Setup program (in my case NTL) and then create a file in the directory <code>$HOME/.mythtv</code> called <code>&lt;video source name&gt;.xmltv</code> (e.g. <code>NTL.xmltv</code> in my case). When I refer to $HOME here I&#8217;m referring to the home directory of the user that you&#8217;re asked to create during the Mythbuntu installation. Within that file you list the XMLTV channel ids you want to retrieve program information for. Here&#8217;s what I have&#8230;</p>
<pre><code>channel northern-ireland.bbc1.bbc.co.uk
channel northern-ireland.bbc2.bbc.co.uk
channel channel4.com
channel discoveryeurope.com
channel e4.channel4.com
channel livingtv.co.uk
channel mtv.co.uk
channel paramountcomedy.com
channel rte-1.rte.ie
channel rte2.rte.ie
channel 1.setanta.com
channel sky-news.sky.com
channel sky-one.sky.com
channel tg4.ie
channel tv3.ie
channel utvlive.com
channel nickelodeon.co.uk</code></pre>
<p>This is the program listing for NTL&#8217;s analogue network in Dublin. Unfortunately (I suppose) Channel 6 isn&#8217;t available from the Radio Times XMLTV feed.</p>
<p>The second problem I had was configuring my wireless network card. The card I have is a Linksys WMP54G (version 4, PCI id 1814:0201). What I did was follow the instructions on this page <a href="https://help.ubuntu.com/community/WifiDocs/Driver/Ndiswrapper">https://help.ubuntu.com/community/WifiDocs/Driver/Ndiswrapper</a>. When it comes to installing the windows drivers I used the files from the directory <code>/Drivers/WMP54Gv4/2KXP</code> on the installation CD that I got with the card. At the end of the process the card still wasn&#8217;t working. The problem was that a kernel module shipped with Ubuntu, namely <code>rt2500pci</code>, was getting loaded before (and hence interfering with) the module I wanted to load, i.e. <code>ndiswrapper</code>. To fix the problem I blacklisted <code>rt2500pci</code> and rebooted. The line I added to <code>/etc/modprobe.d/blacklist</code> was <code>blacklist rt2500pci</code>.</p>
<p>That&#8217;s it, a relatively easy install and nowhere near as timeconsuming or complicated as perfoming a MythTV installation from scratch.</p>
<p>P.S. another useful resource if you&#8217;re stuck is <a href="https://help.ubuntu.com/community/WifiDocs/WirelessTroubleShootingGuide">https://help.ubuntu.com/community/WifiDocs/WirelessTroubleShootingGuide</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2007/10/26/installing-mythbuntu-710/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Hiding &amp; Unhiding the text in a JPasswordField</title>
		<link>http://www.17od.com/2006/12/21/hiding-unhiding-the-text-in-a-jpasswordfield/</link>
		<comments>http://www.17od.com/2006/12/21/hiding-unhiding-the-text-in-a-jpasswordfield/#comments</comments>
		<pubDate>Thu, 21 Dec 2006 13:57:56 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.17od.com/2006/12/21/hiding-unhiding-the-text-in-a-jpasswordfield/</guid>
		<description><![CDATA[JPasswordField is a Java SWING control used to manage password fields. Rather than use a normal JTextField it masks the characters typed by the user with some other character (default is an &#8216;*&#8217;). Very often it&#8217;s useful to see the actual text in this field. One way to do this is to give the user [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://java.sun.com/docs/books/tutorial/uiswing/components/passwordfield.html">JPasswordField</a> is a Java SWING control used to manage password fields. Rather than use a normal JTextField it masks the characters typed by the user with some other character (default is an &#8216;*&#8217;).</p>
<p>Very often it&#8217;s useful to see the actual text in this field. One way to do this is to give the user the option to have a quick peek behind the masked characters by clicking on a checkbox. After adding this feature to <a href="http://www.17od.com/upm">UPM</a> I thought it might share it since it used a feature of JPasswordField I hadn&#8217;t seen before.</p>
<p>The code below shows the action listener I placed on the checkbox used to toggle the password visibility.</p>
<pre><code>hidePasswordCheckbox.addItemListener(new ItemListener() {
    public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
            httpProxyPassword.setEchoChar('*');
        } else {
             httpProxyPassword.setEchoChar((char) 0);
        }
    }
});</code></pre>
<p>Basically the setEchoChar() method sets the character that&#8217;s displayed instead of the actual character. When you set this value to &#8220;0&#8243; JPasswordField doesn&#8217;t perform any masking. It&#8217;s that simple.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2006/12/21/hiding-unhiding-the-text-in-a-jpasswordfield/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Managed Sessions in Hibernate to Ease Unit Testing</title>
		<link>http://www.17od.com/2006/11/06/using-managed-sessions-in-hibernate-to-ease-unit-testing/</link>
		<comments>http://www.17od.com/2006/11/06/using-managed-sessions-in-hibernate-to-ease-unit-testing/#comments</comments>
		<pubDate>Mon, 06 Nov 2006 21:45:23 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://www.17od.com/2006/11/06/using-managed-sessions-in-hibernate-to-ease-unit-testing/</guid>
		<description><![CDATA[If you&#8217;ve ever tried to reuse a session in Hibernate you may have come across this exception&#8230; org.hibernate.SessionException: Session is closed! at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49) at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1319) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301) at $Proxy0.beginTransaction(Unknown Source) .... The reason for this is that Hibernate is using &#8220;thread&#8221; managed sessions. [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve ever tried to reuse a session in <a title="Hibernate" href="http://www.hibernate.org/">Hibernate</a> you may have come across this exception&#8230;</p>
<pre>
org.hibernate.SessionException: Session is closed!
   at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
   at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1319)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
   at $Proxy0.beginTransaction(Unknown Source)
   ....
</pre>
<p>The reason for this is that Hibernate is using &#8220;thread&#8221; managed <a title="sessions" href="http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture.html#architecture-current-session">sessions</a>. With this type of session management Hibernate manages the session for you. When you first attempt to use a session Hibernate will create one and attach it to your local thread. When you commit the transaction in the session Hibernate will automatically close the session meaning it can&#8217;t be reused.</p>
<p>To get around this problem the best option is to use &#8220;managed&#8221; sessions. With managed sessions you&#8217;re in full control of creating, flushing, commiting, and closing sessions. Here&#8217;s how.</p>
<p>In your <code>hibernate.cfg.xml</code> change the property &#8220;current_session_context_class&#8221; to &#8220;managed&#8221;.</p>
<p>To create a session and start a transaction in that session do this&#8230;</p>
<pre>
   org.hibernate.classic.Session session = HibernateUtil.getSessionFactory().openSession();
   session.setFlushMode(FlushMode.MANUAL);
   ManagedSessionContext.bind(session);
   session.beginTransaction();
</pre>
<p>To commit a transaction in the session do this&#8230;</p>
<pre>
   ManagedSessionContext.unbind(HibernateUtil.getSessionFactory());
   session.flush();
   session.getTransaction().commit();
   session.close();
</pre>
<p>To use this code in unit tests I created this base unit test class that all my unit tests extend. Whenever I want to create a new session/transaction I call the method createNewSessionAndTransaction(). To commit the session&#8217;s transaction I call the method commitTransaction().</p>
<pre>
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.ManagedSessionContext;
import util.HibernateUtil;
import junit.framework.TestCase;

/**
 * Abstract unit test with helper methods for managed session control
 */
public abstract class ManagedSessionUnitTest extends TestCase {

   /**
    * Create a new Session.
    *
    * For this method to work, the application managed session strategy has to
    * be enabled. This basically means that the life of a session is controlled
    * by you and and not by Hibernate.
    *
    * To enable the application managed session strategy set the property
    * hibernate.current_session_context_class to "managed".
    *
    * Within this method we create a new session and set the flush mode to
    * MANUAL. This ensures that we have full control over when the session is
    * flushed to the database.
    */
   protected org.hibernate.Session createNewSession() {
      org.hibernate.classic.Session session = HibernateUtil.getSessionFactory().openSession();
      session.setFlushMode(FlushMode.MANUAL);
      ManagedSessionContext.bind(session);
      return (org.hibernate.Session) session;
   }

   /**
    * Start a new Transaction in the given session
    * @param session The session to create the transaction in
    */
   protected void startNewTransaction(Session session) {
      session.beginTransaction();
   }

   /**
    * Shortcut method that creates a new session and begins a transaction in it
    * @return A new session with a transaction started
    */
   protected org.hibernate.Session createNewSessionAndTransaction() {
      Session session = createNewSession();
      startNewTransaction(session);
      return session;
   }

   /**
    * Commit the transaction within the given session. This method unbinds
    * the session from the session context (ManagedSessionContext), flushes
    * the session, commmits the session and then closes the session
    * @param session The session with the transaction to commit
    */
   protected void commitTransaction(Session session) {
      ManagedSessionContext.unbind(HibernateUtil.getSessionFactory());
      session.flush();
      session.getTransaction().commit();
      session.close();
   }

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2006/11/06/using-managed-sessions-in-hibernate-to-ease-unit-testing/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Windows and Mac backups using rdiff-backup</title>
		<link>http://www.17od.com/2006/10/30/windows-and-mac-backups-using-rdiff-backup/</link>
		<comments>http://www.17od.com/2006/10/30/windows-and-mac-backups-using-rdiff-backup/#comments</comments>
		<pubDate>Mon, 30 Oct 2006 15:59:52 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[rdiff-backup]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.17od.com/2006/10/30/windows-and-mac-backups-using-rdiff-backup/</guid>
		<description><![CDATA[I&#8217;ve got two machines that I need to backup, an iMac running OS X 10.0.3 and a Dell running Windows XP. The iMac is the primary home machine with about 13Gb of pictures, music, documents, etc, etc. The Dell is more of a development machine with about 1Gb of files to backup. I wanted a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve got two machines that I need to backup, an iMac running OS X 10.0.3 and a Dell running Windows XP. The iMac is the primary home machine with about 13Gb of pictures, music, documents, etc, etc. The Dell is more of a development machine with about 1Gb of files to backup.</p>
<p>I wanted a backup medium that I could use on both machines. I&#8217;ve never been a big fan of tape backup solutions. They&#8217;re just too expensive and difficult to use in a home environment. Because I don&#8217;t have a huge amount of stuff to backup I decided to go with an external harddrive. They&#8217;re cheap, easy to setup and I could use it on both machines. In the end I went for a <a title="WD My Book" href="http://www.wdmybook.com/">WD My Book</a>. It&#8217;s a little bit more expensive then a basic harddrive and enclosure but not so much that it turned me off. I went with the Premium version because it had the Firewire connection. If I were buying it again I don&#8217;t think I&#8217;d bothered with the Premium edition because when all you&#8217;re backing up is thousands of relatively small files it&#8217;s the processing time that slows the process down not the speed of the connection to the harddrive.</p>
<p>With the medium chosen I then had a look around for some backup software. I wanted something that was opensource and cross platform so that I only had to learn how to use one program. There&#8217;s very little out there that&#8217;s easy to understand and use. The basic programs just don&#8217;t instill any confidence while the feature rich programs are just too complicated and more suited to business environments. The most popular program seems to be <a title="AMANDA" href="http://www.amanda.org/">AMANDA</a>. The problem with AMANDA is that it&#8217;s far too complicated for a simple home backup solution (in my mind anyway). The program I finally settled for was <a title="rdiff-backup" href="http://www.nongnu.org/rdiff-backup/">rdiff-backup</a>. It&#8217;s not too complicated and has all the basic features I need, it&#8217;s open source, it&#8217;s cross platform and it has a user community.</p>
<p>Something that I sort of forgot about up to this point was the filesystem to use on the external harddrive. If you&#8217;re only backing up a Windows machine then I suggest you format your target backup drive as NTFS. If you&#8217;re on Mac then use HFS and if you&#8217;re on Linux use ext3 or whatever you prefer. If however you want to be able to see the same partition from both Windows and Mac (like I do) then you MUST use FAT32. The reason for this is because OS X cannot write to NTFS (only read) and Windows certainly cannot write or read HFS. The only common filesystem that the two OSes can write to is FAT32. The only potential problem with this is that FAT32 only supports files up to 4Gb in size. For me this isn&#8217;t a problem but if you have a lot of videos you may find that some exceed this limit. If this happens then you could just create two partitions on the external harddrive, one HFS for your Mac backups and one NTFS for your Windows backups. You won&#8217;t be able to see the HFS partition from Windows but if that&#8217;s not a problem for you then this might be the best approach all round. The other drawback with FAT32 is that Windows will only allow you to create a partition that&#8217;s 32Gb in size. The strange thing is that Windows can reference a FAT32 partition that&#8217;s up to 2Tb in size. To create a partition greater that 32Gb WD have a tool for the My Book called the <a title="WD FAT32 Formatter" href="http://wdc.custhelp.com/cgi-bin/wdc.cfg/php/enduser/std_adp.php?p_faqid=1364&#038;p_created=1117047065&#038;p_sid=dL84lpli&#038;p_lva=&#038;p_sp=cF9zcmNoPTEmcF9zb3J0X2J5PSZwX2dyaWRzb3J0PSZwX3Jvd19jbnQ9NTImcF9wcm9kcz0mcF9jYXRzPSZwX3B2PSZwX2N2PSZwX3NlYXJjaF90eXBlPXNlYXJjaF9mbmwmcF9wYWdlPTEmcF9zZWFyY2hfdGV4dD1GQVQzMiBmb3JtYXR0ZXI*&#038;p_li=&#038;p_topview=1">WD FAT32 Formatter</a>. There&#8217;s probably generic tools out there that will do this for any harddrive.</p>
<p><strong>rdiff-backup on Mac OS X</strong><br />
The first machine I backed up was the iMac. Because I might be restoring onto a completely clean machine I created a folder on the external harddrive with all the software that&#8217;s needed to install and run rdiff-backup. Into this directory I put&#8230;</p>
<ul>
<li><a href="http://www.nongnu.org/rdiff-backup">rdiff-backup 1.1.5</a></li>
<li><a href="http://librsync.sourceforge.net">librsync 0.9.7</a></li>
<li><a href="http://www.17od.com/wordpress/wp-content/uploads/2007/11/fs_abilitiespy.patch" title="A patch I needed get rdiff-backup working on OS X">A patch I needed get rdiff-backup working on OS X</a> (I got the patch from this useful post <a href="http://katastrophos.net/andre/blog/?p=19">http://katastrophos.net/andre/blog/?p=19</a>)</li>
</ul>
<p><strong>Installing librsync on Mac OS X</strong><br />
=> tar -xzvf librsync-0.9.7.tar.gz<br />
=> cd librsync-0.9.7<br />
=> ./configure<br />
=> make all<br />
=> make check (not necessary)<br />
=> sudo make install</p>
<p><strong>Installing rdiff-backup </strong><strong>on Mac OS X</strong><br />
=> tar -xzvf rdiff-backup-1.1.5.tar.gz<br />
=> cp fs_abilities.py.patch rdiff-backup-1.1.5/rdiff_backup<br />
=> cd rdiff-backup-1.1.5/rdiff_backup<br />
=> patch &lt; fs_abilities.py.patch<br />
=> cd ..<br />
=> sudo python setup.py install<br />
(Create symbolic links in your bin directory for the two rdiff programs)<br />
=> sudo ln -s /System/Library/Frameworks/Python.framework/Versions/2.3/bin/rdiff-backup /usr/bin/rdiff-backup<br />
=> sudo ln -s /System/Library/Frameworks/Python.framework/Versions/2.3/bin/rdiff-backup-statistics /usr/bin/rdiff-backup-statistics</p>
<p><strong>Preparing rdiff-backup on Mac OS X<br />
</strong>rdiff-backup lets you explicitly list the files and directories you want to backup in an external file called the &#8220;globbing filelist&#8221;. Here&#8217;s what&#8217;s in mine&#8230;</p>
<pre>/Users/adriansmith/Desktop
/Users/adriansmith/dev
/Users/adriansmith/Documents
/Users/adriansmith/Movies
/Users/adriansmith/Music
/Users/adriansmith/Pictures
/Users/adriansmith/Shared
/Users/adriansmith/Sites</pre>
<p>A very important point to note (although more important on the windows platform) is that this file should be saved in UNIX format. If it&#8217;s saved in Windows format rdiff-backup will not read it correctly.</p>
<p><strong>Running rdiff-backup on Mac OS X<br />
</strong></p>
<pre>rdiff-backup -v5 --print-statistics --include-globbing-filelist '/Volumes/My Book/instructions/mac/files-to-include.txt' --exclude-special-files --exclude / / '/Volumes/My Book/mac'</pre>
<p><strong><em>-v5</em></strong> : Verbosity level<br />
<em><strong> &#8211;print-statistics</strong></em> : When the backup is finished a summary will be displayed<br />
<em><strong> &#8211;include-globbing-filelist</strong></em> : Followed by the file that contains the list of files &#038; directories to backup<br />
<em><strong> &#8211;exclude-special-files</strong></em> : Exclude all device files, fifo files, socket files, and symbolic links<br />
<em><strong> &#8211;exclude /</strong></em> : Excludes everything from the root directory (weird I know but by including this you&#8217;re saying that you only want to include the files/directories specifically mentioned in the globbing file<br />
<em><strong> /</strong></em> : The source directory<br />
<em><strong> &#8216;/Volumes/My Book/mac&#8217;</strong></em> : The destination directory, in this case a directory called mac on my external harddrive</p>
<p><strong>rdiff-backup on Windows XP</strong><br />
On my Windows machine I again created a folder on the external harddrive containing all the software needed to get rdiff-backup up and running. It contains&#8230;</p>
<ul>
<li><a href="http://www.cygwin.com/">Cygwin</a> (because rdiff-backup requires a POSIX operating system, like Linux or Mac OS X)</li>
<li><a href="http://www.nongnu.org/rdiff-backup">rdiff-backup 1.1.5</a></li>
<li><a href="http://librsync.sourceforge.net/">librsync 0.9.7</a></li>
<li><a href="http://www.17od.com/wordpress/wp-content/uploads/2007/11/rpath-fsync.patch" title="A patch needed get rdiff-backup working on Windows">A patch needed get rdiff-backup working on Windows</a></li>
</ul>
<p><strong>Installing Cygwin on Windows XP<br />
</strong>=> Run setup.exe<br />
=> Go with the default selected packages to install but select the following as well,</p>
<ul>
<li>Devel/ autoconf, automake, binutils, gcc, make, patchutils</li>
<li>Interpreters/ python</li>
<li>Web/ wget</li>
</ul>
<p><strong>Installing librsync on Windows XP<br />
</strong>=> tar -xzvf librsync-0.9.7.tar.gz<br />
=> cd librsync-0.9.7<br />
=> ./configure &#8211;prefix=/usr &#8211;bindir=/bin &#8211;libdir=/lib<br />
=> make all<br />
=> make install</p>
<p><strong>Installing rdiff-backup on Windows XP</strong><br />
=> tar -xzvf rdiff-backup-1.1.5.tar.gz<br />
=> cp rpath-fsync.patch rdiff-backup-1.1.5/rdiff_backup<br />
=> cd rdiff-backup-1.1.5/rdiff_backup<br />
=> patch &lt; rpath-fsync.patch<br />
=> cd ..<br />
=> python setup.py install</p>
<p><strong>Preparing rdiff-backup on Windows XP</strong><br />
To run rdiff-backup I again created a file containing all the files and directories I wanted to backup. Here&#8217;s what it contains&#8230;</p>
<pre>/cygdrive/c/Documents and Settings/Adrian Smith/My Documents
/cygdrive/c/projects</pre>
<p>IMPORTANT: This file MUST be saved in UNIX format. If you use Notepad or any other program that saves in Windows format rdiff-backup will not work. I use <a href="http://www.lancs.ac.uk/staff/steveb/cpaap/pfe/default.htm">PFE</a> but there are plenty of other equally capable editors out there.</p>
<p><strong>Running rdiff-backup on Windows XP<br />
</strong>Finally, to run rdiff-backup&#8230;</p>
<pre>rdiff-backup -v5 --print-statistics --include-globbing-filelist /cygdrive/e/instructions/windows/files-to-include.txt --exclude /cygdrive/c /cygdrive/c /cygdrive/e/dell</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2006/10/30/windows-and-mac-backups-using-rdiff-backup/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Where&#8217;s JAVA_HOME on my Mac OS X?</title>
		<link>http://www.17od.com/2005/07/13/wheres-java_home-on-my-mac-os-x/</link>
		<comments>http://www.17od.com/2005/07/13/wheres-java_home-on-my-mac-os-x/#comments</comments>
		<pubDate>Thu, 14 Jul 2005 00:07:06 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[mac]]></category>

		<guid isPermaLink="false">http://70.103.16.167/~onesevod/?p=7</guid>
		<description><![CDATA[I was installing CruiseControl on my Mac the other day when I realized that I needed to have JAVA_HOME set. Running which java returned /usr/bin/java. This was a symbolic link to the file /System/Library/Frameworks/JavaVM.framework/Commands/java. Eventually I figured out that the path I was looking for was /System/Library/Frameworks/JavaVM.framework/Home.]]></description>
			<content:encoded><![CDATA[<p>I was installing CruiseControl on my Mac the other day when I realized that I needed to have JAVA_HOME set. Running <code>which java</code> returned <code>/usr/bin/java</code>. This was a symbolic link to the file <code>/System/Library/Frameworks/JavaVM.framework/Commands/java</code>. Eventually I figured out that the path I was looking for was <code>/System/Library/Frameworks/JavaVM.framework/Home</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2005/07/13/wheres-java_home-on-my-mac-os-x/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Installing Qt 4.0 on Windows</title>
		<link>http://www.17od.com/2005/07/05/installing-qt-40-on-windows/</link>
		<comments>http://www.17od.com/2005/07/05/installing-qt-40-on-windows/#comments</comments>
		<pubDate>Wed, 06 Jul 2005 00:49:33 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[qt]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://70.103.16.167/~onesevod/?p=8</guid>
		<description><![CDATA[For anyone who&#8217;s tried installing Qt4 on Windows you&#8217;ll no doubt have had a few problems. Here&#8217;s the steps I had to go through to get it working&#8230; Make sure you have MinGW installed. I&#8217;m using version 4.1.0. Download the file qt-win-opensource-desktop-4.0.0.zip from Trolltech&#8217;s website Extract it to the directory where you want to install [...]]]></description>
			<content:encoded><![CDATA[<p>For anyone who&#8217;s tried installing Qt4 on Windows you&#8217;ll no doubt have had a few problems. Here&#8217;s the steps I had to go through to get it working&#8230;</p>
<ul>
<li>Make sure you have MinGW installed. I&#8217;m using version 4.1.0.</li>
<li>Download the file qt-win-opensource-desktop-4.0.0.zip from Trolltech&#8217;s website</li>
<li>Extract it to the directory where you want to install Qt, e.g. <code>c:\qt\4.0.0</code></li>
<li>Open a command prompt and cd to the directory <code>c:\qt\4.0.0</code></li>
<li>Run the configure program like this, <code>configure -platform win32-g++</code>. You have to use the win32-g++ platform (MinGW) because win32-msvc (MS Visual Studio) is not supported in the open source version of Qt (see <a href="http://www.qtforum.org/thread.php?threadid=9100&#038;sid=38a4dab94f7f8a2c131af25811788111&#038;threadview=0&#038;hilight=&#038;hilightuser=0&#038;page=1">here</a> for a lively debat on the topic). If you try running <code>configure -platform win32-msvc</code> you&#8217;ll get to accept the license agreement but the configure program will just exit straight away with no explaination of what happened</li>
<li>Ensure that the MinGW bin directory is in your PATH environment variable. It&#8217;s very important that if you have MSYS installed that it is NOT in your PATH. If it is then the next step will fail because it picks up the <strong>cd</strong> program from MSYS and fails when trying to cd to windows formatted paths (i.e. paths using \ instead of /)</li>
<li>Run <code>mingw32-make.</code> Note that this step takes quite some time (> 1 hour). Note also that you&#8217;ll need at about 2GB of disk space to hold all the files built as part of this step.</li>
<li>Finally add <code>c:\qt\4.0.0\bin</code> to your PATH environment variable. Ensure also that MinGW is on your PATH so that the Qt applications can find the MinGW binaries at runtime.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2005/07/05/installing-qt-40-on-windows/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Installing BerkeleyDB, Apache &amp; Subversion on Debian 3 (woody)</title>
		<link>http://www.17od.com/2005/03/26/installing-berkeleydb-apache-subversion-on-debian-3-woody/</link>
		<comments>http://www.17od.com/2005/03/26/installing-berkeleydb-apache-subversion-on-debian-3-woody/#comments</comments>
		<pubDate>Sun, 27 Mar 2005 04:35:42 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[berkeleydb]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://70.103.16.167/~onesevod/?p=9</guid>
		<description><![CDATA[Install Berkeley DB Go to http://www.sleepycat.com/download/index.shtml and download BerkeleyDB 4.2.52 Download the patches numbered like this patch.4.2.52.? Extract the BerkeleyDB compressed file Copy all the patch files into the base directory just extracted Apply the patches individually using&#8230;patch -p0 &#60; [patchfile] cd into the build_unix directory in the extracted directory Run&#8230;../dist/configure Run&#8230;make Ensure you&#8217;re logged [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Install Berkeley DB</strong></p>
<ol>
<li>Go to http://www.sleepycat.com/download/index.shtml and download BerkeleyDB 4.2.52</li>
<li>Download the patches numbered like this  <em>patch.4.2.52.?</em></li>
<li>Extract the BerkeleyDB compressed file</li>
<li>Copy all the patch files into the base directory just extracted</li>
<li>Apply the patches individually using&#8230;<em>patch -p0 &lt; [patchfile]</em></li>
<li>cd into the <em>build_unix</em> directory in the extracted directory</li>
<li>Run&#8230;<em>../dist/configure</em></li>
<li>Run&#8230;<em>make</em></li>
<li>Ensure you&#8217;re logged in as root and run&#8230;<em>make install</em> (installs to /usr/local/BerkeleyDB.4.2)</li>
<li>Add the line <em>/usr/local/BerkeleyDB.4.2/lib</em> to the file<em>/etc/ld.so.conf</em></li>
<li>Run <em>ldconfig</em> to update the library cache with the BerkeleyDB libraries</li>
</ol>
<p><strong>Install Apache</strong></p>
<ol>
<li>Ensure that the following packages are installed. If they&#8217;re not just do an <em>apt-get install</em> to download and install them&#8230;<em>autoconf libtool openssl libssl-dev zlib1g zlib1g-dev</em></li>
<li>Download tha latest version of Apache 2 from http://httpd.apache.org/download.cgi</li>
<li>Extract the Apache compressed file</li>
<li>cd in the extracted directory</li>
<li>Run&#8230;<em>./configure &#8211;enable-dav &#8211;enable-so &#8211;enable-ssl &#8211;with-dbm=db4 &#8211;with-berkeley-db=/usr/local/BerkeleyDB.4.2 &#8211;enable-deflate</em></li>
<li>Run&#8230;<em>make</em></li>
<li>Ensure you&#8217;re logged in as root and run&#8230;<em>make install</em> (installs to /usr/local/apache2)</li>
<li>Edit the file <em>/usr/local/apache2/conf/httpd.conf</em> and update the <em>User</em> &#038; <em>Group</em> tags to <em>www-data</em> (Assuming of course that you have that user &#038; group)</li>
</ol>
<p><strong>Install Subversion</strong></p>
<ol>
<li>Download the latest version of Subversion from http://subversion.tigris.org/getting_subversion.html</li>
<li>Extract the Subversion compressed file</li>
<li>Run&#8230;<em>./configure &#8211;with-ssl &#8211;with-berkeley-db=/usr/local/BerkeleyDB.4.2 &#8211;with-zlib</em></li>
<li>Run&#8230;<em>make</em></li>
<li>Ensure you&#8217;re logged in as root and run&#8230;<em>make install</em></li>
</ol>
<p><strong>Configure Apache &#038; Subversion</strong></p>
<ol>
<li>Create a directory to hold your repositories, something like <em>/usr/local/svn</em></li>
<li>Change the ownership on the directory to the <em>www-user</em> user (or whoever you set the User tag to in httpd.conf)</li>
<li>Add users to Apache using this command&#8230;<em>htpasswd -cm /etc/svn-auth-file &lt;name&gt;</em>. Leave out the <em>c</em> switch if the file already exists</li>
<li>Add the following section to <em>/usr/local/apache2/conf/httpd.conf</em>
<pre>LoadModule dav_svn_module     modules/mod_dav_svn.so
DeflateFilterNote Input instream
DeflateFilterNote Output outstream
DeflateFilterNote Ratio ratio
LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
CustomLog logs/deflate_log deflate

&lt;Location /svn&gt;
DAV svn
SVNParentPath /usr/local/svn
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/svn-auth-file
Require valid-user
SetOutputFilter DEFLATE
SetInputFilter DEFLATE
&lt;/Location&gt;
</pre>
<p>These config entries will password protect your repositry and allow for data sent between clients and Apache to be compressed</li>
</ol>
<p><strong>Starting Apache</strong></p>
<ol>
<li>Ensure you&#8217;re logged in as root and run&#8230;<em>/usr/local/apache2/bin/apachectl start</em></li>
</ol>
<p>The next step is to try and get Apache using SSL because Basic authentication uses plain text when transmitting the password from the client to the server. <a href="http://tortoisesvn.tigris.org/docs/TortoiseSVN_en/ch03.html#tsvn-serversetup-apache-6">This</a> article seems to do the trick.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2005/03/26/installing-berkeleydb-apache-subversion-on-debian-3-woody/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

