<?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>Jayway Team Blog &#187; Henrik Bernström</title>
	<atom:link href="http://blog.jayway.com/author/henrikbernstrom/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jayway.com</link>
	<description>Sharing Experience</description>
	<lastBuildDate>Sat, 11 Feb 2012 10:33:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>How to use user metadata in post types via Advanced Custom Fields in WordPress</title>
		<link>http://blog.jayway.com/2012/01/14/how-to-use-user-metadata-in-post-types-via-advanced-custom-fields-in-wordpress/</link>
		<comments>http://blog.jayway.com/2012/01/14/how-to-use-user-metadata-in-post-types-via-advanced-custom-fields-in-wordpress/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 23:01:31 +0000</pubDate>
		<dc:creator>Henrik Bernström</dc:creator>
				<category><![CDATA[Dynamic languages]]></category>
		<category><![CDATA[advanced custom fields]]></category>
		<category><![CDATA[custom post types]]></category>
		<category><![CDATA[metadata]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[repeater]]></category>
		<category><![CDATA[user profile]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://blog.jayway.com/?p=11831</guid>
		<description><![CDATA[To get the most out of this article a basic knowledge of PHP, WordPress, custom post types and Advanced Custom Fields is required. If you've ever needed custom data input for your WordPress posts or pages (or any other kind of custom post type) then Advanced Custom Fields (ACF) is the shit! It's flexible, extensible [...]]]></description>
			<content:encoded><![CDATA[<p><em>To get the most out of this article a basic knowledge of PHP, WordPress, custom post types and Advanced Custom Fields is required.</em></p>
<p>If you've ever needed custom data input for your WordPress posts or pages (or any other kind of custom post type) then <a href="http://plugins.elliotcondon.com/advanced-custom-fields/" title="Advanced Custom Field WordPress plugin" target="_blank">Advanced Custom Fields (ACF)</a> is the shit! It's flexible, extensible and frequently improved by Elliot Condon. Simply brilliant!</p>
<p>I've been using ACF in a couple of projects now and in the current one I needed to be able to present WordPress users as hosts for different kinds of events, showing user a profile photo and a custom user metadata type. There was no obvious, flexible and easy to administer option available, or at least I couldn't find one, so I started thinking about what could be done with ACF and user profile custom fields. I decided to try it out.</p>
<h3>Adding metadata to the user profile</h3>
<p>To start with I had to add a couple of custom metadata fields to the user profile.</p>
<div>
<pre class="brush: php; ruler: true; gutter: false;">
&lt;?php
class JwCustomUserMeta {

	function __construct(){
		add_action( 'show_user_profile', array($this, 'jw_add_custom_user_profile_fields') );
		add_action( 'edit_user_profile', array($this, 'jw_add_custom_user_profile_fields') );
		add_action( 'personal_options_update', array($this, 'jw_save_custom_user_profile_fields')  );
		add_action( 'edit_user_profile_update', array($this, 'jw_save_custom_user_profile_fields')  );
	}

	function jw_add_custom_user_profile_fields( $user ) {
	?>
<h3>&lt;?php _e('Extra Profile Information', 'your_textdomain'); ?></h3>
<table class="form-table">
<tr>
<th>
					<label for="jw_title">&lt;?php _e('Title', 'your_textdomain'); ?></label>
				</th>
<td>
<input type="text" name="jw_title" id="jw_title" value="&lt;?php echo esc_attr( get_the_author_meta( 'jw_title', $user->ID ) ); ?>" class="regular-text" />
					<span class="description">&lt;?php _e('Please enter your work title.', 'your_textdomain'); ?></span>
				</td>
</tr>
<tr>
<th>
					<label for="jw_phone"><?php _e('Phone', 'your_textdomain'); ?></label>
				</th>
<td>
<input type="text" name="jw_phone" id="jw_phone" value="&lt;?php echo esc_attr( get_the_author_meta( 'jw_phone', $user->ID ) ); ?>" class="regular-text" />
					<span class="description">&lt;?php _e('Please enter your phone number.', 'your_textdomain'); ?></span>
				</td>
</tr>
</table>

	&lt;?php }

	function jw_save_custom_user_profile_fields( $user_id ) {
		if ( !current_user_can( 'edit_user', $user_id ) )
			return FALSE;
		update_usermeta( $user_id, 'jw_title', $_POST['jw_title'] );
		update_usermeta( $user_id, 'jw_phone', $_POST['jw_phone'] );
	}
} ?>
</pre>
</div>
<h3>Creating the User Meta field type</h3>
<p>To be able to nicely select users as hosts in the custom post type Event I had to create a new Advanced Custom Field type; User Meta. It is in many ways a rip-off of the Select core field type differenting in the way that it is not configurable with respect to options (the values of the select input field) but the options are populated with all the registered WordPress users, instead. </p>
<p>Here's the code. I've kept most of the code in the create_field function to support  ACF field options, that might be a requirement for some:</p>
<div>
<pre class="brush: php; ruler: true; gutter: false;">
&lt;?php

class acf_UserMeta extends acf_Field
{

	function __construct($parent)
	{
		// do not delete!
    	parent::__construct($parent);

    	// set name / title
    	$this->name = 'user_meta'; // variable name (no spaces / special characters / etc)
		$this->title = __("User Meta",'acf'); // field label (Displayed in edit screens)

   	}

	function create_field($field)
	{
		global $wpdb;

		// get the wordpress users
		$wp_user_search = $wpdb->get_results("SELECT ID, display_name FROM $wpdb->users ORDER BY display_name");

		$choices = array();

		// loop through users and add them as choices
		foreach ( $wp_user_search as $user ) {
			$user_id = (int) $user->ID;
			$display_name  = stripslashes($user->display_name);
			$choices[$user_id] = $display_name;
		}

		$field['choices'] = $choices;

		// defaults
		$field['value'] = isset($field['value']) ? $field['value'] : array();
		$field['multiple'] = isset($field['multiple']) ? $field['multiple'] : false;
		$field['allow_null'] = isset($field['allow_null']) ? $field['allow_null'] : false;
		$field['optgroup'] = isset($field['optgroup']) ? $field['optgroup'] : false;

		// no choices
		if(empty($field['choices']))
		{
			echo '

' . __("No choices to choose from",'acf') . '

';
			return false;
		}

		// multiple select
		$multiple = '';
		if($field['multiple'] == '1')
		{
			$multiple = ' multiple="multiple" size="5" ';
			$field['name'] .= '[]';
		} 

		// html
		echo '
<select id="' . $field['name'] . '" class="' . $field['class'] . '" name="' . $field['name'] . '" ' . $multiple . ' >';	

		// null
		if($field['allow_null'] == '1')
		{
			echo '
<option value="null"> - Select - </option>

';
		}

		// loop through values and add them as options
		foreach($field['choices'] as $key => $value)
		{
			if($field['optgroup'])
			{
				// this select is grouped with optgroup
				echo '<optgroup label="'.$key.'">';
				if($value)
				{
					foreach($value as $id => $label)
					{
						$selected = '';
						if(is_array($field['value']) && in_array($id, $field['value']))
						{
							// 2. If the value is an array (multiple select), loop through values and check if it is selected
							$selected = 'selected="selected"';
						}
						else
						{
							// 3. this is not a multiple select, just check normaly
							if($id == $field['value'])
							{
								$selected = 'selected="selected"';
							}
						}
						echo '
<option value="'.$id.'" '.$selected.'>'.$label.'</option>

';
					}
				}
				echo '</optgroup>';
			}
			else
			{
				$selected = '';
				if(is_array($field['value']) && in_array($key, $field['value']))
				{
					// 2. If the value is an array (multiple select), loop through values and check if it is selected
					$selected = 'selected="selected"';
				}
				else
				{
					// 3. this is not a multiple select, just check normaly
					if($key == $field['value'])
					{
						$selected = 'selected="selected"';
					}
				}
				echo '
<option value="'.$key.'" '.$selected.'>'.$value.'</option>

';
			}
		}

		echo '</select>

';
	}
}
?>
</pre>
</div>
<p>So now, I can use this field as any other basic Advanced Custom Field; as standalone, in repeaters and flexible content. It's a very simple solution that stores the user id as value which can then be retrieved in templates to use when fetching information about the user via <code>get_userdata($user_id);</code></p>
<div id="attachment_11835" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-ACF-group.png" rel="lightbox"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-ACF-group-300x239.png" alt="" title="UserMeta-in-ACF-group" width="300" height="239" class="size-medium wp-image-11835" /></a><p class="wp-caption-text">Defining a User Meta field in the event ACF group.</p></div>
<div id="attachment_11837" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-posttype.png" rel="lightbox"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-posttype-300x92.png" alt="" title="UserMeta-in-posttype" width="300" height="92" class="size-medium wp-image-11837" /></a><p class="wp-caption-text">Using the User Meta field to assign hosts to the event post type.</p></div>
<h3>Implementing it in templates</h3>
<p>Below I will list a piece of code where the field is used in a repeater, listing event hosts. </p>
<div>
<pre class="brush: php; ruler: true; gutter: false;">
<h3>Hosted by</h3>

&lt;?php while(the_repeater_field('event_hosts', $post->ID)):
	$user_id = get_sub_field('event_host', $post->ID);
	$user_info = get_userdata($user_id);?>
<div class="photo-container"><a href="/author/&lt;?php echo $user_info->user_login; ?>">
		<img class="photo" src="&lt;?php echo content_url() . '/uploads/userphoto/' . $user_info->userphoto_thumb_file; ?>" />
	</a>

&lt;?php echo $user_info->display_name; ?>

&lt;?php echo $user_info->jw_title; ?>
</div>

&lt;?php endwhile; ?>
</pre>
</div>
<h3>The result</h3>
<div id="attachment_11836" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-action.png" rel="lightbox"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2012/01/UserMeta-in-action-300x235.png" alt="" title="UserMeta-in-action" width="300" height="235" class="size-medium wp-image-11836" /></a><p class="wp-caption-text">The final result.</p></div>
<p>To learn more about how to create your own Advanced Custom Field types, see <a href="http://plugins.elliotcondon.com/advanced-custom-fields/documentation/creating-your-own-field/" title="Video tutorial on creating your own advanced custom field type." target="_blank">this video tutorial</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2012/01/14/how-to-use-user-metadata-in-post-types-via-advanced-custom-fields-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using s3cmd to Backup your WordPress Installation</title>
		<link>http://blog.jayway.com/2011/10/02/using-s3cmd-to-backup-your-wordpress-data/</link>
		<comments>http://blog.jayway.com/2011/10/02/using-s3cmd-to-backup-your-wordpress-data/#comments</comments>
		<pubDate>Sun, 02 Oct 2011 21:05:18 +0000</pubDate>
		<dc:creator>Henrik Bernström</dc:creator>
				<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[backupwordpress]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[crontab]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[s3]]></category>
		<category><![CDATA[s3cmd]]></category>
		<category><![CDATA[shell scripting]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://blog.jayway.com/?p=9849</guid>
		<description><![CDATA[This article will explain, in a few short steps, how to backup your WordPress installation to Amazon S3 service. It will deal with Ubuntu as operating system and Amazon EC2 for hosting but is not limited to such an environment. Prerequisits are an Amazon account for the S3 service, a WordPress installation and knowledge of [...]]]></description>
			<content:encoded><![CDATA[<p>This article will explain, in a few short steps, how to backup your WordPress installation to Amazon S3 service. It will deal with Ubuntu as operating system and Amazon EC2 for hosting but is not limited to such an environment. Prerequisits are an Amazon account for the S3 service, a WordPress installation and knowledge of these products.</p>
<h2>How to backup WordPress</h2>
<p>There are numerous plugins for WordPress when it comes to backup. I have learnt to appreciate the plugin BackUpWordPress as it not only backs up your database but also all the files within the installation. </p>
<p><a href="http://hmn.md/backupwordpress/" title="BackUpWordPress">http://hmn.md/backupwordpress/</a></p>
<p>There are a few number (though quite complete) of configuration options like</p>
<p>- manual or daily scheduled backups<br />
- number of backups to keep<br />
- whether to include files or database or both</p>
<p>The backups are stored on disk on the path of your choice and could also be attempted to be emailed. Having this kind of backup data makes it very comfortable to restore your WordPress installation.</p>
<p>But what if your complete machine/instance is failing? On, for example Amazon EC2 one should take snapshots of instances when the setup of these change but this does not apply to content changes. Restoring from a snapshot does not bring back newly created or updated content from, for example WordPress. That is, moving those WordPress backup files to a safer place becomes vital. So, s3cmd to the rescue.</p>
<h2>What is s3cmd?</h2>
<p>Extracted from its' homepage:</p>
<p><em>"S3cmd is a command line tool for uploading, retrieving and managing data in Amazon S3. It is best suited for power users who don't fear command line. It is also ideal for scripts, automated backups triggered from cron, etc."</em></p>
<p><a href="http://s3tools.org/s3cmd" title="s3cmd">http://s3tools.org/s3cmd</a></p>
<p>At the time of writing s3cmd requires Python 2.4 or newer and some pretty common Python modules. Installing it is merely a matter of running:</p>
<pre class="brush: shell; ruler: true; auto-links: false; smart-tabs: false;">sudo apt-get install s3cmd</pre>
<p>To configure it run</p>
<pre class="brush: shell; ruler: true; auto-links: false; smart-tabs: false;">s3cmd --configure</pre>
<p>You will be asked for the two keys of your Amazon account - copy and paste them from your confirmation email or from your Amazon account page.</p>
<p>To list all your buckets run</p>
<pre class="brush: shell; ruler: true; auto-links: false; smart-tabs: false;">s3cmd ls</pre>
<p>and to list the content of a bucket run</p>
<pre class="brush: shell; ruler: true; auto-links: false; smart-tabs: false;">s3cmd ls s3://[bucket name]</pre>
<p>Now, you could use 's3cmd put' to upload and 's3cmd remove' to remotely remove specific files but then you would have to do some scripting to select these specific files and to keep the bucket contents to an acceptable size. There is another option that simply syncs the content of your local directory to the remote bucket, doing the removal automatically, namely 's3cmd sync'.</p>
<pre class="brush: shell; ruler: true; auto-links: false; smart-tabs: false;">s3cmd sync --delete-removed [source directory] s3://[bucket name]</pre>
<p>The source directory is naturally replaced with the directory of where you put your WordPress backups. </p>
<h2>Scheduling it</h2>
<p>To make it a little easier to schedule via crontab you preferrably put the sync command in a shell script, for example 'sync-wp-backups.sh'</p>
<pre class="brush: bash/shell; ruler: true; auto-links: false; smart-tabs: false;">#!/bin/bash

/usr/bin/s3cmd sync --delete-removed [source directory] s3://[bucket name]</pre>
<p>To schedule this script run</p>
<pre class="brush: bash/shell; ruler: true; auto-links: false; smart-tabs: false;">crontab -e</pre>
<p>which brings you into editing the cron job with the editor of your choice. For example you could edit the crontab file to schedule it to run daily at 23:30 (11:30 PM)</p>
<pre class="brush: bash/shell; ruler: true; auto-links: false; smart-tabs: false;">30 23 * * * /home/ubuntu/sync-wp-backups.sh >> /home/ubuntu/s3-backup.log</pre>
<p>which logs the output to file (s3-backup.log).</p>
<p>That's it! Now I have a number of days of backup automatically synced from the Amazon instance running WordPress to a more fail safe S3 bucket. At least I sleep a lot better with this in place.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2011/10/02/using-s3cmd-to-backup-your-wordpress-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blogging Among the Clouds</title>
		<link>http://blog.jayway.com/2009/05/07/blogging-among-the-clouds/</link>
		<comments>http://blog.jayway.com/2009/05/07/blogging-among-the-clouds/#comments</comments>
		<pubDate>Thu, 07 May 2009 18:31:57 +0000</pubDate>
		<dc:creator>Henrik Bernström</dc:creator>
				<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[dreamhost]]></category>
		<category><![CDATA[ebs]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[s3]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://79.125.9.149/?p=1619</guid>
		<description><![CDATA[Up until now this WordPress blog has been hosted by DreamHost, a company with a good reputation and a solid knowledge in hosting. Unfortunately, the server we've been located on, Trafficante, have lately had some problems with stability and performance and DreamHost have also had some MySQL stability issues. This, plus the fact that we've [...]]]></description>
			<content:encoded><![CDATA[<p>Up until now this WordPress blog has been hosted by <a href="http://dreamhost.com/aboutus.html">DreamHost</a>, a company with a good reputation and a solid knowledge in hosting. Unfortunately, the server we've been located on, Trafficante, have lately had some problems with stability and performance and DreamHost have also had some MySQL stability issues. This, plus the fact that we've had some really good experience with <a href="http://aws.amazon.com/">Amazons' Web Services</a> has made us take the leap, up among the clouds. </p>
<p>That said, I must also give credit to DreamHost for always being very helpful and supporting when needed.</p>
<p>If you want to know what we did to gain the speed needed for a lift-of, keep on reading.</p>
<h3>Exporting the Existing Database</h3>
<p>I really like MySQL, but when it comes to encoding for character sets and collations there seems to be such a complexity in the details that users often get lost and configure it the wrong way. The UTF-8 configured database we used on DreamHost worked just fine together with our WordPress installation but it turned out to be impossible to export a correct UTF-8 version for importing into our new environment. And I tried a lot of things. Really. I'm not going to go into details but to sum it up I had to sit down and do kind of manual replacements of the swedish specific characters in the database export. Lucky me this blog is in english. </p>
<p>Anyway, I had ssh access to the Trafficante server and could use this connection to export the database from the DreamHost MySQL server by issueing:</p>
<pre class="bash">&nbsp;
mysqldump --default-character-<span style="color: #007800;">set=</span>UTF8 -u <span style="color: #7a0874; font-weight: bold;">&#91;</span>user<span style="color: #7a0874; font-weight: bold;">&#93;</span> -p -h <span style="color: #7a0874; font-weight: bold;">&#91;</span>host<span style="color: #7a0874; font-weight: bold;">&#93;</span>.dreamhosters.com <span style="color: #7a0874; font-weight: bold;">&#91;</span>database<span style="color: #7a0874; font-weight: bold;">&#93;</span> -r <span style="color: #7a0874; font-weight: bold;">&#91;</span>output<span style="color: #7a0874; font-weight: bold;">&#93;</span>.sql
&nbsp;</pre>
<p>This resulted in a database dump later used for importing into the new MySQL instance.</p>
<h3>Setting up the Amazon EC2 Instance</h3>
<p>To make your Amazon life easier start with installing the Firefox plugins <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=609">Elasticfox</a> and <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=771">S3 Organizer</a>. These tools give you a GUI view of the somewhat more complex underlying details of Amazon. </p>
<p>Amazons' cloud solution is based on a user account. There are no start-up fees, you only pay for what you use. So if you still haven't got an account, <a href="http://www.amazon.com/gp/aws/registration/registration-form.html">sign-up now</a>. The rest of this article assumes you have signed up and set up accounts for <a href="http://aws.amazon.com/ec2/">Amazon EC2</a>, <a href="http://aws.amazon.com/s3/">Amazon S3</a> and <a href="http://aws.amazon.com/ebs/">Amazon EBS</a>. Start by reading the <a href="http://docs.amazonwebservices.com/AWSEC2/latest/GettingStartedGuide/">EC2 Getting Started Guide</a> and don't stop reading until you have created an ssh key pair, a security group and have a server instance running.</p>
<p>Now you should also have a private key and a certificate in your <em>${EC2_HOME}</em> (preferrably <em>${HOME}/.ec2/</em>) folder of your local computer. These two files should also be uploaded to your instance /mnt folder to make it possible to bundle and upload your images to your S3 "bucket(s)" (buckets are one level deep folders/directories). Make sure you put them in the /mnt folder to prevent them from being bundled with the image and thereby increasing the risk of having your identity revealed.</p>
<p>Bundling, by the way, should be done when you've made changes to your server instance that you don't want to loose. The result of a bundling and uploading is an image with a specific Amazon Image Id (AMI ID) reflecting the state of your server instance at the moment of bundling. You also have to register the image with the manifest file created for you. If you do that you could then safely close down your instance and have it up and running again by issuing the ec2-run-instances command with the AMI ID as parameter. A way to save money.</p>
<p>Bundling and uploading was made easier for me as I used two scripts created by my colleague <a href="/author/ulriksandberg">Ulrik</a>. I put these scripts in the /root folder.</p>
<pre class="bash">bundle-myself.<span style="color: #c20cb9; font-weight: bold;">sh</span>:
&nbsp;
<span style="color: #808080; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">prg=</span>`<span style="color: #c20cb9; font-weight: bold;">basename</span> $<span style="color: #000000;">0</span>`
<span style="color: #007800;">dest=</span>/mnt
<span style="color: #007800;">image=</span>blog-image
&nbsp;
<span style="color: #007800;">USAGE=</span><span style="color: #ff0000;">&quot;Usage: $prg &lt;datetime&gt;
&nbsp;
Example:
% $prg 20090415-1000
Bundling into $dest/$image-20090415-1000.manifest.xml&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$#</span> -ne <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
  <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;$USAGE&quot;</span>
  <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #007800;">date=</span>$<span style="color: #000000;">1</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Bundling into $dest/$image-$date.manifest.xml&quot;</span>
ec2-bundle-vol --debug -k /mnt/pk-PRIVATE_KEY.pem -c /mnt/cert-CERTIFICATE.pem -u USER_ACCOUNT_ID -d <span style="color: #007800;">$dest</span> -p <span style="color: #007800;">$image</span>-<span style="color: #007800;">$dat</span>
e -r i386
&nbsp;</pre>
<pre class="bash">upload-myself.<span style="color: #c20cb9; font-weight: bold;">sh</span>:
&nbsp;
<span style="color: #808080; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">prg=</span>`<span style="color: #c20cb9; font-weight: bold;">basename</span> $<span style="color: #000000;">0</span>`
<span style="color: #007800;">dest=</span>/mnt
<span style="color: #007800;">image=</span>blog-image
&nbsp;
<span style="color: #007800;">USAGE=</span><span style="color: #ff0000;">&quot;Usage: $prg &lt;date&gt;
&nbsp;
Example:
% $prg 20090415-1000
Uploading bundled AMI parts to https://s3.amazonaws.com:443/[S3_BUCKET] ...
Uploaded blog-image-20090415-1000.part.00 to https://s3.amazonaws.com:443/[S3_BUCKET]/blog-image-20090415-1000.part.00.
...&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$#</span> -ne <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
  <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;$USAGE&quot;</span>
  <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #007800;">date=</span>$<span style="color: #000000;">1</span>
ec2-upload-bundle --retry -m <span style="color: #007800;">$dest</span>/<span style="color: #007800;">$image</span>-<span style="color: #007800;">$date</span>.manifest.xml -b blog-images -a <span style="color: #7a0874; font-weight: bold;">&#91;</span>PUBLIC_KEY<span style="color: #7a0874; font-weight: bold;">&#93;</span> -s <span style="color: #7a0874; font-weight: bold;">&#91;</span>PRIVATE_KEY<span style="color: #7a0874; font-weight: bold;">&#93;</span>
&nbsp;</pre>
<p>Another thing I needed was a static IP address for my instance. To solve this I used Amazons Elastic IP service which doesn't cost anything as long as the generated IP address is in use. So, I generated an Elastic IP address and assigned it to the instance.</p>
<h3>Installing Necessary Software</h3>
<p>The blog require <a href="http://httpd.apache.org/">Apache2</a>, <a href="http://www.php.net/">Php5</a>, <a href="http://www.mysql.com">MySQL</a> and the <a href="http://www.phpgd.com/">Php GD graphics package</a>, to start with. This was easily installed using <a href="http://en.wikipedia.org/wiki/Advanced_Packaging_Tool">Advanced Packaging Tool</a>, apt-get:</p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">sudo</span> apt-get update</span>
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">sudo</span> apt-get <span style="color: #c20cb9; font-weight: bold;">install</span> apache2 php5 mysql-server php5-mysql php5-gd</span>
&nbsp;</pre>
<h3>Setting up the Database for EBS</h3>
<p>EBS volumes are, as you might know, more persistent than EC2 instances and will survive if instances go down. Volumes are attached to the instance and could as well be detached and re-attached to new instances. As EBS volumes are not 100% reliable you should also take snapshots of your database data and have it uploaded to an S3 bucket. All this is nicely described in <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1663">Eric Hammonds' EBS and MySQL tutorial</a>, so I urge you to read it if you haven't yet. </p>
<p>The only thing I sidestepped in the tutorial was the MySQL configuration to point out the data and log directories. Instead I used symbolic links:</p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">ln</span> -s /vol/lib/mysql/ /var/lib/mysql</span>
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">ln</span> -s /vol/log/mysql/ /var/log/mysql</span>
&nbsp;</pre>
<p>The tutorial also walks you through automatic snapshots which requires the EC2 command line tools. Here is <a href="https://help.ubuntu.com/community/EC2APITools">a nice tutorial on setting these tools up on Ubuntu</a>.</p>
<p>I had to tweak the environment variable settings in ec2-snapshot-xfs-mysql.pl script from</p>
<pre>
BEGIN {
  $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
}
</pre>
<p>to</p>
<pre>
BEGIN {
  $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/root/ec2-api-tools/bin';
  $ENV{EC2_CERT} = '/mnt/cert-CERTIFICATE.pem';
  $ENV{EC2_PRIVATE_KEY} = '/mnt/pk-PRIVATE_KEY.pem';
  $ENV{EC2_HOME} = '/root/ec2-api-tools';
  $ENV{HOME} = '/root';
  $ENV{JAVA_HOME} = '/usr/lib/jvm/java-1.5.0-sun';
}
</pre>
<p>to get the snapshotting to fully work. I also wrapped the ec2-snapshot-xfs-mysql.pl script for a more convenient way to handle the input:</p>
<pre>/root/snapshot-myself.sh

#!/bin/sh
mountpoint=/vol
volume_id=[VOLUME_ID]

su -c "/root/ec2-snapshot-xfs-mysql.pl ${mountpoint} ${volume_id} > /vol/cron.log"
</pre>
<p>To automatize the snapshotting I set up a simple crontab job by issueing:</p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># crontab -e</span>
&nbsp;</pre>
<p>and then edited it like this</p>
<pre>
05 */6 * * * sh /root/snapshot-myself.sh
</pre>
<p>which makes the job run five minutes past every six hours, every day.</p>
<p>I also had to set the timezone info to apply to our local time. The easiest way I've found out of setting this for a Linux server is like this:</p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">ln</span> -sf /usr/share/zoneinfo/Europe/Stockholm /etc/localtime</span>
&nbsp;</pre>
<h3>Configuring MySQL</h3>
<p>To configure MySQL for UTF-8 content make sure the <em>/etc/mysql/my.cnf</em> file contains the following:</p>
<pre>
[client]
default-character-set=utf8

[mysqld]
#
# * Basic Settings
#
init_connect='SET collation_connection = utf8_general_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_general_ci
default-character-set=utf8
skip-character-set-client-handshake
</pre>
<p>Now, if you haven't yet, go on and start your MySQL server. You need to create your wordpress database. It's as simple as:</p>
<pre class="sql">&nbsp;
<span style="color: #808080; font-style: italic;"># mysql -u [user] -p</span>
&gt; <span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> <span style="color: #66cc66;">&#91;</span>database_name<span style="color: #66cc66;">&#93;</span>
&nbsp;</pre>
<p>To create the user with which WordPress will access the database:</p>
<pre class="sql">&nbsp;
&gt; <span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">ALL</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #66cc66;">&#91;</span>database_name<span style="color: #66cc66;">&#93;</span>.* <span style="color: #993333; font-weight: bold;">TO</span> <span style="color: #ff0000;">'[user]'</span>@<span style="color: #ff0000;">'localhost'</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'[password]'</span>;
&nbsp;</pre>
<p>And to import your database dump into the newly created database:</p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># mysql -u <span style="color: #7a0874; font-weight: bold;">&#91;</span>user<span style="color: #7a0874; font-weight: bold;">&#93;</span> -p <span style="color: #7a0874; font-weight: bold;">&#91;</span>database_name<span style="color: #7a0874; font-weight: bold;">&#93;</span> &lt; <span style="color: #7a0874; font-weight: bold;">&#91;</span>output<span style="color: #7a0874; font-weight: bold;">&#93;</span>.sql</span>
&nbsp;</pre>
<p>You shouldn't need to specify any character set or collation when importing thanks to the configuration done in <em>/etc/mysql/my.cnf</em>.</p>
<p>In order for us to stick with our domain name and have no downtime we needed to use the instances IP address until we were finished testing. This means I had to replace two properties in the database to prevent the blog from redirecting to the original host; the '<em>siteurl</em>' and '<em>blogurl</em>' properties residing in the <em>option_value</em> column of the <em>wp_options</em> table. The commands</p>
<pre class="sql">&nbsp;
<span style="color: #808080; font-style: italic;"># mysql -u [user] -p</span>
&gt; <span style="color: #993333; font-weight: bold;">UPDATE</span> wp_options <span style="color: #993333; font-weight: bold;">SET</span> option_value=<span style="color: #ff0000;">'http://[ip_address]/wordpress/'</span> <span style="color: #993333; font-weight: bold;">WHERE</span> option_name=<span style="color: #ff0000;">'siteurl'</span>
&gt; <span style="color: #993333; font-weight: bold;">UPDATE</span> wp_options <span style="color: #993333; font-weight: bold;">SET</span> option_value=<span style="color: #ff0000;">'http://[ip_address]/wordpress/'</span> <span style="color: #993333; font-weight: bold;">WHERE</span> option_name=<span style="color: #ff0000;">'blogurl'</span>
&nbsp;</pre>
<p>fixed this. As soon as the DNS info was propagated throughout the Internet this was reset to <em>"http://blog.jayway.com/wordpress"</em> from within the WordPress admin interface.</p>
<h3>Apache Configuration</h3>
<p>Our WordPress installation makes use of permalinks and redirects to <a href="http://feedburner.google.com/">FeedBurner</a> for RSS statistics. This is based on <em>.htaccess</em> redirects (at least that's how we've solved it) which in turn is dependent on the Apache redirect module. So, in order to make this to work I had to enable that. </p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">sudo</span> a2enmod rewrite</span>
&nbsp;</pre>
<p>Easy as that! One more thing on redirections. I had to configure Apache to allow redirection directives specified in the <em>.htaccess</em> file by changing the <em>/etc/apache2/sites-available/default</em> configuration of the <em><VirtualHost *></em> element from</p>
<pre class="xml">&nbsp;
	<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;Directory</span> /var/www<span style="font-weight: bold; color: black;">/&gt;</span></span>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/Directory<span style="font-weight: bold; color: black;">&gt;</span></span></span>
&nbsp;</pre>
<p>to</p>
<pre class="xml">&nbsp;
	<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;Directory</span> /var/www<span style="font-weight: bold; color: black;">/&gt;</span></span>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;----------</span>
		Order allow,deny
		allow from all
	<span style="font-weight: bold; color: black;">&lt;/Directory<span style="font-weight: bold; color: black;">&gt;</span></span></span>
&nbsp;</pre>
<h3>Securing the WordPress Admin Interface</h3>
<p>Again, I choose to refer to detailed and well written sources. Here are the two articles I followed to create a self-signed certificate and to configure Apache to use it.</p>
<ul>
<li><a href="http://www.tc.umn.edu/~brams006/selfsign.html">Creating a self-signed certificate</a></li>
<li><a href="http://www.tc.umn.edu/~brams006/selfsign_ubuntu.html">Configuring Apache for SSL on Ubuntu</a></li>
</ul>
<p>To enable https access from the "outside world" I also edited the group policy to open up port 443. This could easily be done via the Elasticfox Firefox plugin mentioned earlier.</p>
<h3>Installing and Configuring WordPress</h3>
<p>The default location for Apache httpd server for reading content is <em>/var/www/</em>. If you, as I did, have an existing WordPress installation you can simply copy this to the new server. I ended up having it located at <em>/var/www/wordpress/</em> on the Amazon instance.</p>
<p>Once the database connection properties in the <em>wp-config.php</em> wordpress configuration file was adapted to the new environment I was able to access the WordPress installation via a browser and the Amazon instances' IP address. Sweet!</p>
<p>And as we have our WordPress installation in a separate "<em>/wordpress</em>" folder instead of in the document root of Apache we need to specify, in WordPress admin settings, that the '<em>Site URL</em>' should be "<em>${host}/wordpress</em>" but the<em> 'Blog URL</em>' should simply say "<em>${host}</em>" to prevent the resulting URL from containing "<em>/wordpress/...</em>". This also requires that we move the <em>.htaccess</em> and <em>index.php</em> files from within our "<em>/wordpress</em>" folder and up one level to "<em>/var/www/</em>", in our case. </p>
<p>In the <em>index.php</em> file, make sure to change from</p>
<pre class="php">&nbsp;
<span style="color: #808080; font-style: italic;">/** Loads the WordPress Environment and Template */</span>
<span style="color: #b1b100;">require</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'./wp-blog-header.php'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;</pre>
<p>to </p>
<pre class="php">&nbsp;
<span style="color: #808080; font-style: italic;">/** Loads the WordPress Environment and Template */</span>
<span style="color: #b1b100;">require</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'./wordpress/wp-blog-header.php'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;</pre>
<p>If or when specifying the permalinks, WordPress must have write access to the <em>.htaccess</em> file, so 'chmod' that file. </p>
<pre class="bash">&nbsp;
<span style="color: #808080; font-style: italic;"># <span style="color: #c20cb9; font-weight: bold;">chmod</span> <span style="color: #000000;">755</span> .htaccess</span>
&nbsp;</pre>
<p>Otherwise it will complain and simply print out the <em>.htaccess</em> modification it tried to modify with and you are left to change it manually, instead.</p>
<h3>Sending Mail from WordPress</h3>
<p>Mailing is used in WordPress when generating new passwords to users, among others. We also use it to send data backups to the administator of the blog. </p>
<p>Setting up a mail server isn't a trivial task. I gave it a thought but quickly put it aside in favour of the simple WordPress plugin <a href="http://wordpress.org/extend/plugins/wp-mail-smtp/">WP Mail SMTP</a> as I realized I could make use of our existing corporate mail server. It was a breeze to configure the plugin with the necessary mail user credentials.</p>
<p>So, here we are. Sailing these fluffy clouds. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2009/05/07/blogging-among-the-clouds/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Honoring our Industry Gurus</title>
		<link>http://blog.jayway.com/2009/03/27/honoring-our-industry-gurus/</link>
		<comments>http://blog.jayway.com/2009/03/27/honoring-our-industry-gurus/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 14:25:35 +0000</pubDate>
		<dc:creator>Henrik Bernström</dc:creator>
				<category><![CDATA[Events]]></category>
		<category><![CDATA[andy warhol]]></category>
		<category><![CDATA[art]]></category>
		<category><![CDATA[celebration]]></category>
		<category><![CDATA[gimp]]></category>
		<category><![CDATA[inspiration]]></category>
		<category><![CDATA[interior design]]></category>
		<category><![CDATA[james duncan davidson]]></category>
		<category><![CDATA[james gosling]]></category>
		<category><![CDATA[joshua bloch]]></category>
		<category><![CDATA[marilyn monroe]]></category>
		<category><![CDATA[paintings]]></category>
		<category><![CDATA[rod johnson]]></category>
		<category><![CDATA[thomas dagsberg]]></category>

		<guid isPermaLink="false">http://blog.jayway.com/?p=1415</guid>
		<description><![CDATA[The Halmstad office where I belong is a quite nice place to be. It's clean, there are five desks and a sofa, and... yeah, that's about it. Practical but perhaps a bit boring. We have these white and rather dull walls with nothing but whiteboards hanging on them so we figured, what could we do [...]]]></description>
			<content:encoded><![CDATA[<p>The Halmstad office where I belong is a quite nice place to be. It's clean, there are five desks and a sofa, and... yeah, that's about it. Practical but perhaps a bit boring.</p>
<p>We have these white and rather dull walls with nothing but whiteboards hanging on them so we figured, what could we do to make it look better, more inviting and inspiring? Yeah, you could go with these modern wall stickers, which are easy to work with and looks good but not very personal, really. Could we do something that more connects to what we do for a living? </p>
<p>It took some time to get to it but finally we came up with the idea to depict the people in our industry that have meant something to us, that have made our lives as developers easier. Simply put; gurus. We finally went for the "Warhol Marilyn Monroe" way as the form of how we would portrait these gurus, which would both be quite easy but also colourful and warm. </p>
<p>As there is only room for some five'ish paintings or so in our office, we had to really cut tight in the selection of whom to choose for our paintings. Asking the other Jayway offices revealed quite a lot and brainstorming ourselves resulted in too many, really. The final five was finally set to (in alphabetic order, to be safe)  <a href="http://en.wikipedia.org/wiki/Joshua_Bloch">Joshua Bloch</a>, Thomas Dagsberg, <a href="http://en.wikipedia.org/wiki/James_Duncan_Davidson">James Duncan Davidson</a>, <a href="http://en.wikipedia.org/wiki/James_Gosling">James Gosling</a> and <a href="http://en.wikipedia.org/wiki/Spring_framework">Rod Johnson</a>. Thomas Dagsberg, you ask? It's our CEO...</p>
<p><center></p>
<table cellspacing="15" border="0">
<tr>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3111.jpg" rel="lightbox" title="Fabulous Five"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3111.jpg" width="100" height="100" alt="Fabulous Five" /></a></td>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3114.jpg" rel="lightbox" title="Honored by Jayway"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3114.jpg" width="100" height="100" alt="Honored by Jayway" /></a></td>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3124.jpg" rel="lightbox" title="Gosling watching over us"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3124.jpg" width="100" height="100" alt="Gosling watching over us" /></a></td>
</tr>
<tr>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3125.jpg" rel="lightbox" title="Rod is backing up"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3125.jpg" width="100" height="100" alt="Rod is backing up" /></a></td>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3126.jpg" rel="lightbox" title="Paintings and suitable literature"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3126.jpg" width="100" height="100" alt="Paintings and suitable literature" /></a></td>
<td><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3127.jpg" rel="lightbox" title="Thomas - Man in the middle"><img src="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/dsc_3127.jpg" width="100" height="100" alt="Thomas - Man in the middle" /></a></td>
</tr>
</table>
<p></center></p>
<p>The paintings were digitally produced using Gimp with a 180ppi resolution on a MacBook Pro. They were printed and framed on a 700x700x15mm format on high quality canvas by Kanfoto produktion & försäljning in Halmstad.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2009/03/27/honoring-our-industry-gurus/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mavenizing the Liferay Plugin SDK</title>
		<link>http://blog.jayway.com/2009/03/14/mavenizing-the-liferay-plugin-sdk/</link>
		<comments>http://blog.jayway.com/2009/03/14/mavenizing-the-liferay-plugin-sdk/#comments</comments>
		<pubDate>Sat, 14 Mar 2009 08:58:00 +0000</pubDate>
		<dc:creator>Henrik Bernström</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[User Experience]]></category>
		<category><![CDATA[archetype]]></category>
		<category><![CDATA[artifact]]></category>
		<category><![CDATA[liferay]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[maven2]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[portlet]]></category>
		<category><![CDATA[sdk]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.jayway.com/?p=1094</guid>
		<description><![CDATA[Liferay is the leading Open Source enterprise portal platform in the Java market. It's certainly an impressive piece of software. I've been following it for some time now and the product is improving a great deal in many areas, perhaps most in end user usability. One area that, in my opinion, could still be improved [...]]]></description>
			<content:encoded><![CDATA[<p>Liferay is the leading Open Source enterprise portal platform in the Java market. It's certainly an impressive piece of software. I've been following it for some time now and the product is improving a great deal in many areas, perhaps most in end user usability.</p>
<p>One area that, in my opinion, could still be improved is the development environment. It may be a heck of a good build system <a href="http://www.liferay.com">Liferay</a> has come up with, but at the bottom line it takes time to learn it and to just start studying it you easily become a bit uncertain. It consists of homegrown ant scripts. To have a flatter learning curve for newcomers <a href="http://maven.apache.org/">Maven 2</a> might be suitable.</p>
<p>Anyway, I sat down one evening some time ago and looked into how Maven 2 could be used for creating Jsp Portlets for Liferay. Some hours later the work had resulted in a new archetype for creating Liferay Jsp Portlets. </p>
<p><a href="http://svn.liferay.com/browse/plugins/trunk/tools/portlet_tmpl">The structure and content of the standard Liferay Jsp Portlet can be viewed here.</a></p>
<h3>So, what did I do?</h3>
<p>1. I followed these instructions to manipulate the Jsp Portlet part of Liferay's plugin SDK into a maven archetype:</p>
<p><a href="http://maven.apache.org/guides/mini/guide-creating-archetypes.html">http://maven.apache.org/guides/mini/guide-creating-archetypes.html</a></p>
<p>This involved editing these property and xml files:</p>
<pre>liferay-plugin-package.properties
name=${artifactId}
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=MIT
</pre>
<pre class="xml">portlet.xml
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span><span style="font-weight: bold; color: black;">?&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;portlet-app</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot;</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span> <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span> <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;portlet<span style="font-weight: bold; color: black;">&gt;</span></span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;portlet-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>jspPortlet<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/portlet-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;display-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>${artifactId}<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/display-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;portlet-class<span style="font-weight: bold; color: black;">&gt;</span></span></span>${groupId}.JSPPortlet<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/portlet-class<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;init-param<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;name<span style="font-weight: bold; color: black;">&gt;</span></span></span>view-jsp<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;value<span style="font-weight: bold; color: black;">&gt;</span></span></span>/view.jsp<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/value<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/init-param<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;expiration-cache<span style="font-weight: bold; color: black;">&gt;</span></span></span>0<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/expiration-cache<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;supports<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;mime-type<span style="font-weight: bold; color: black;">&gt;</span></span></span>text/html<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/mime-type<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/supports<span style="font-weight: bold; color: black;">&gt;</span></span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;portlet-info<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;title<span style="font-weight: bold; color: black;">&gt;</span></span></span>${artifactId}<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/title<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;short-title<span style="font-weight: bold; color: black;">&gt;</span></span></span>${artifactId}<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/short-title<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;keywords<span style="font-weight: bold; color: black;">&gt;</span></span></span>${artifactId}<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/keywords<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/portlet-info<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>administrator<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>guest<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>power-user<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>user<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/role-name<span style="font-weight: bold; color: black;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/security-role-ref<span style="font-weight: bold; color: black;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/portlet<span style="font-weight: bold; color: black;">&gt;</span></span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/portlet-app<span style="font-weight: bold; color: black;">&gt;</span></span></span>
&nbsp;</pre>
<p>to insert ${artifactId} and ${groupId} for the portlet name and package structure. These files are part of the file list finally being wrapped up within the archetype and used to generate the resulting portlet from Maven 2.</p>
<p>2. I ran '<strong>mvn install</strong>' on that particular archetype to have it installed in my local repository.</p>
<p>3. I used the archetype to create a new Liferay Jsp Portlet artifact:</p>
<pre>
mvn archetype:create -DarchetypeGroupId=com.liferay.maven.archetypes.portlet.jsp
  -DarchetypeArtifactId=liferay-jsp-portlet
  -DarchetypeVersion=1.0-SNAPSHOT
  -DgroupId=[my.package]
  -DartifactId=[MyFirstLiferayJspPortlet]
</pre>
<p>4. I stepped into the artifact and ran '<strong>mvn install</strong>' on it which generated my MyFirstLiferayJspPortlet-1.0-SNAPSHOT.war.</p>
<p>5. I then uploaded the war file to my portal instance via the Liferay admin GUI Plugin Installer.</p>
<p>6. Et voila. It worked, showing up in the portal.</p>
<p>And of course, worth mentioning, to have a development environment up and running in eclipse in seconds this is all you have to do:</p>
<pre>
1. mvn eclipse:add-maven-repo -Declipse.workspace=[full-path-to-workspace]

2. mvn eclipse:eclipse
</pre>
<p>To have the archetype play with the existing build situation of Liferay it would probably need to be generated from some ant target and be based on the portlet template in subversion located at "plugins/tools/portlet_tmpl/" to have it follow updates of Liferay.</p>
<p><a href="http://blog.jayway.com/wordpress/wp-content/uploads/2009/03/jspportlet-archetype.zip">Here you can download the final result, as a zipped archetype.</a></p>
<p>If a generated archetype like this was to be uploaded to a public maven repository, working from above point #3 and down is what would be necessary for a developer to have a project and all the necessary property and xml files (correctly edited with package structures and all) in place for a Liferay Jsp Portlet development environment. It could at least become a complement to the Plugins SDK. And yes, it could for sure still be enhanced. For example, there is no JSPPortletTest class generated for the JSPPortlet class.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2009/03/14/mavenizing-the-liferay-plugin-sdk/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

