<?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>Colabrativ, Inc. &#187; Technical</title>
	<atom:link href="http://www.colabrativ.com/category/technical/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.colabrativ.com</link>
	<description>An Experiment Documentation and Electronic Notebook Provider</description>
	<lastBuildDate>Tue, 28 Oct 2014 04:44:35 +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>Scalable Vector Graphics Pattern Examples</title>
		<link>http://www.colabrativ.com/scalable-vector-graphics-svg-pattern-examples/</link>
		<comments>http://www.colabrativ.com/scalable-vector-graphics-svg-pattern-examples/#comments</comments>
		<pubDate>Wed, 26 Feb 2014 19:23:23 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[Examples]]></category>
		<category><![CDATA[Scalable Vector Graphics]]></category>
		<category><![CDATA[SVG]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=845</guid>
		<description><![CDATA[Scalable Vector Graphics (SVG) is a markup language for creating two dimensional graphic images. It is commonly used in HTML in combination with CSS and Javascript. If you are new to SVG, I would suggest visiting the W3schools.com SVG Tutorial. &#8230; <a href="http://www.colabrativ.com/scalable-vector-graphics-svg-pattern-examples/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.w3.org/Graphics/SVG/" target="_blank">Scalable Vector Graphics</a> (SVG) is a markup language for creating two dimensional graphic images.  It is commonly used in HTML in combination with CSS and Javascript.  If you are new to SVG, I would suggest visiting the <a href="http://www.w3schools.com/svg/" target="_blank">W3schools.com SVG Tutorial</a>. </p>
<p>An SVG pattern is used to fill any SVG element such as a circle, line or rectangle.  In this post I will give several examples of SVG patterns, and describe how they are constructed.  The technical documentation on SVG 1.1 (Second Edition) can be found at <a href="http://www.w3.org/TR/SVG11/pservers.html" target="_blank">http://www.w3.org/TR/SVG11/pservers.html</a>.</p>
<h3>Basic Setup of an SVG Pattern</h3>
<p>The pattern is defined in a <code>defs</code> element in an <code>svg</code> element, and referenced in the <code>fill</code> attribute of the SVG element using a <code>url</code> link to the pattern.  Shown below is a simple dot pattern.  The dot pattern is made up of a <code>circle</code> element in a <code>pattern</code> element.</p>
<table>
<tr>
<td>
      <svg height="21" width="45" version="1.1" xmlns="http://www.w3.org/2000/svg"><circle cx="30" cy="11" r="8" style="stroke:none; fill:red;" /></svg><br />
<span style="font-size:8pt;">Scale&nbsp;=&nbsp;2X</span>
    </td>
<td>The circle element in this example has a radius of 4 (r=&#8221;4&#8243;) and is centered at 5,5 (cx=&#8221;5&#8243; and cy=&#8221;5&#8243;).  The image of the filled circle has been enlarged two-fold. </p>
<p><code>&lt;circle x="1" y="1" cx="5" cy="5" r="4" style="stroke:none; fill:red;" /&gt;</code>
    </td>
</tr>
<tr>
<td>
      <svg height="24" width="45" version="1.1" xmlns="http://www.w3.org/2000/svg"><rect x="19" y="1" width="22" height="22" style="stroke-width:1; stroke:black; fill:none;" /><circle cx="30" cy="12" r="8" style="stroke: none; fill: red;" /></svg><br />
<span style="font-size:8pt;">Scale&nbsp;=&nbsp;2X</span>
    </td>
<td>Circle element in <code>pattern</code> element:  The circle element above is placed in a pattern element that has a width and height of 11 (<code>width="11" height="11"</code>).  The pattern has the Id (<code>id="dots-4-11"</code>) used to link to in other SVG elements, and <code>patternUnits="userSpaceOnUse"</code> attributes.  I have put a box around the pattern in the figure to our left that is not part of the dots-4-11 pattern. </p>
<p><code>&lt;pattern id="dots-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="5" cy="5" r="4" style="stroke:none; fill:red;" /&gt;<br />
&lt;/pattern&gt;</code>
    </td>
</tr>
<tr>
<td>
      <svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>
<pattern id="dots-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse"><circle cx="5" cy="5" r="4" style="stroke:none; fill:red;" /></pattern></defs>  <rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#dots-4-11);" /></svg>
    </td>
<td>Using the dots-4-11 pattern in an SVG rectangle element (&lt;rect&gt;):  A pattern is repeated both vertically and horizontally to completely fill SVG element they are referenced in.  The dots-4-11 pattern is placed in a <code>defs</code> element above the the SVG &lt;rect&gt; element that will use it.  In the 50 x 60 &lt;rect&gt; element, the dots-4-11 pattern is linked to the pattern in the style attribute using the link url(#dots-4-11).  A 1 pixel boarder has been add to the &lt;rect&gt; element (<code>stroke-width:1; stroke:black;</code>).</p>
<p><code>&lt;svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;defs&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pattern id="dots-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="5" cy="5" r="4" style="stroke:none; fill:red;" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/pattern&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/defs&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&lt;rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#dots-4-11);" /&gt;<br />
&lt;/svg&gt;</code>
    </td>
</tr>
</table>
<h3>SVG Diagonal Dot Pattern</h3>
<table>
<tr>
<td>
      <svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>
<pattern id="diagonal-dots-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><circle cx="5" cy="5" r="4" style="stroke:none; fill:blue;" /></pattern></defs>  <rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#diagonal-dots-4-11);" /></svg>
    </td>
<td>We can take the circles-4-11 pattern above, and rotated it by 45&deg; to produce a diagonal circle pattern using the pattern attribute patternTransform (<code>patternTransform="rotate(45)"</code>).</p>
<p><code>&lt;pattern id="diagonal-dots-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;circle cx="5" cy="5" r="4" style="stroke:none; fill:blue;" /&gt;<br />
&lt;/pattern&gt;</code>
    </td>
</tr>
</table>
<h3>SVG Diagonal Circle Pattern</h3>
<table>
<tr>
<td>
      <svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>
<pattern id="diagonal-circles-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><circle cx="5" cy="5" r="4" style="stroke-width:2; stroke:green; fill:none;" /></pattern></defs>  <rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#diagonal-circles-4-11);" /></svg>
    </td>
<td>We can take the dots-4-11 pattern above, and set stroke-width, stroke and fill to 2, green and none, respectively (<code>stroke-width:4; stroke:green; fill:none;</code>) to create green circles.</p>
<p><code>&lt;pattern id="diagonal-circles-4-11" x="0" y="0" width="11" height="11" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;circle cx="5" cy="5" r="4" style="stroke-width:2; stroke:green; fill:none;" /&gt;<br />
&lt;/pattern&gt;</code>
    </td>
</tr>
</table>
<h3>SVG Diagonal Stripes Pattern</h3>
<table>
<tr>
<td>
      <svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>
<pattern id="diagonal-stripes-4-8" x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><rect x="0" y="0" width="4" height="8" style="stroke:none; fill:purple;" /></pattern></defs>  <rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#diagonal-stripes-4-8)" /></svg>
    </td>
<td>To create a diagonally striped pattern, we fill one half the pattern with a purple rectangle (<code>&lt;rect&gt;</code>), and then rotate the pattern by 30&deg; (<code>patternTransform="rotate(30)"</code>).</p>
<p><code>&lt;pattern id="diagonal-stripes-4-8" x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(30)"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;rect x="0" y="0" width="4" height="8" style="stroke:none; fill:purple;" /&gt;<br />
&lt;/pattern&gt;</code>
    </td>
</tr>
</table>
<h3>SVG Grid Pattern</h3>
<table>
<tr>
<td>
      <svg height="50" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>
<pattern id="grid-4-10" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse"><rect x="0" y="0" width="10" height="4" style="stroke:none; fill:orange;" /><rect x="3" y="3" width="4" height="10" style="stroke:none; fill:orange;" /></pattern></defs>  <rect x="1" y="1" height="48" width="58" style="stroke-width:1; stroke:black; fill:url(#grid-4-10)" /></svg>
    </td>
<td>To create a grid pattern, we create a plus sign in the pattern using two 4 x 10 rectangles (<code>&lt;rect&gt;</code>), one running horizontally (<code>width="10" height="4"</code>) and the other running vertically (<code>width="4" height="10"</code>) through the 10 x 10 pattern. </p>
<p><code>&lt;pattern id="grid-4-10" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;rect x="0" y="0" width="10" height="4" style="stroke:none; fill:orange;" /&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;rect x="3" y="3" width="4" height="10" style="stroke:none; fill:orange;" /&gt;<br />
&lt;/pattern&gt;</code></p>
<p>A grid can be changed into a plaid pattern by changing the <code>fill-opacity</code> to 0.5.
    </td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/scalable-vector-graphics-svg-pattern-examples/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating SSL Certificates for Google Web Toolkit Running on Apache HTTPD and Tomcat on Amazon Web Services EC2</title>
		<link>http://www.colabrativ.com/creating-ssl-certificates-for-google-web-toolkit-running-on-apache-httpd-and-tomcat-on-amazon-web-services-ec2/</link>
		<comments>http://www.colabrativ.com/creating-ssl-certificates-for-google-web-toolkit-running-on-apache-httpd-and-tomcat-on-amazon-web-services-ec2/#comments</comments>
		<pubDate>Sat, 31 Aug 2013 16:29:08 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Elastic Compute Cloud]]></category>
		<category><![CDATA[GWT]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=737</guid>
		<description><![CDATA[This post is a follow-up article to my August 27, 2012 article on Creating Self-Signed Certificates for Google Web Toolkit Running on Apache HTTPD and Tomcat on Amazon Web Services EC2. Server Configuration Creating and installing a Secure Sockets Layer &#8230; <a href="http://www.colabrativ.com/creating-ssl-certificates-for-google-web-toolkit-running-on-apache-httpd-and-tomcat-on-amazon-web-services-ec2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This post is a follow-up article to my August 27, 2012 article on <a target="_blank" href="http://www.colabrativ.com/self-signed-certificates-gwt-applications-apache-http-tomcat/">Creating Self-Signed Certificates for Google Web Toolkit Running on Apache HTTPD and Tomcat on Amazon Web Services EC2.</a></p>
<h3>Server Configuration</h3>
<p>Creating and installing a <a target="_blank" href="http://en.wikipedia.org/wiki/Secure_Sockets_Layer">Secure Sockets Layer (SSL)</a> certificate on a server should be a relatively simple task.  However, most of the documentation relating to this task is confusing.  Most of the confusion arises from the fact that there are a multitude of different server configurations that utilize the SSL to complete secure transactions over the web.  In order not to add to this confusion, the following tutorial will refer to the following server configuration: </p>
<table style="border:0px solid white;">
<tr>
<td style="border:0px solid white;">Server:</td>
<td style="border:0px solid white;">64 bit Linux server running on <a target="_blank" href="http://aws.amazon.com/">Amazon Web Services</a> <a target="_blank" href="http://aws.amazon.com/ec2/">Elastic Compute Cloud (EC2)</a> server based on AMI ami-3bc9997e</td>
</tr>
<tr>
<td style="border:0px solid white;">Server&nbsp;Software:</td>
<td style="border:0px solid white;"><a target="_blank" href="http://httpd.apache.org/ABOUT_APACHE.html">Apache HTTP Server (HTTPD)</a> and <a target="_blank" href="http://tomcat.apache.org/">Apache Tomcat</a></td>
</tr>
<tr>
<td style="border:0px solid white;">Applications&nbsp;Type:</td>
<td style="border:0px solid white;"><a target="_blank" href="https://developers.google.com/web-toolkit/">Google Web Toolkit</a> and Java servlets</td>
</tr>
</table>
<p>In this post I will describe:</p>
<ol>
<li><a href="#create-keystore">Creating a Java Keystore</a></li>
<li><a href="#CSR-generation">Certificate Signing Request (CSR) Generation</a></li>
<li><a href="#check-CSR">Check the Certificate Signing Request (CSR)</a></li>
<li><a href="#loading-keystore">Loading the Certificates into the Java Keystore</a></li>
<li><a href="#extract-key">Extracting the Key from the Keystore</a></li>
<li><a href="#configure-ssl-conf">Configuring Apache Server (HTTPD) ssl.conf</a></li>
<li><a href="#add-keystore-to-tomcat">Adding Keystore to Tomcat&#8217;s server.xml</a></li>
</ol>
<h3 id="create-keystore">Creating of a Java Keystore</h3>
<p>Here we will use a <a target="_blank" href="http://docs.oracle.com/javase/6/docs/api/java/security/KeyStore.html">Java KeyStore</a> to generate and store the SSL key and certificates.  One of the limitations to this approach is that you must start by creating the KeyStore first.  SSL utilities such as <a target="_blank" href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/keytool.html">Java keytool</a> and <a target="_blank" href="http://www.openssl.org/">OpenSSL</a> do not have the ability to create a keystore from an existing certificate and key.  In particular, there is no way to put the key in the keystore. </p>
<div class="codeBox">
<p>First we will create and open to the directory /etc/pki/tls/keystore.  The  <strong>keytool</strong> command that creates the keystore, we need to supply the following: </p>
<ul>
<li><strong>keystore</strong> file name: <span style="color: blue">demo.colabrativ.com.jks</span></li>
<li><strong>key algorythm (keyalg)</strong>: <span style="color: blue">RSA</span></li>
<li><strong>alias</strong>: <span style="color: blue">demo</span></li>
<li><strong>keysize</strong>: <span style="color: blue">2048</span>  As of January 1, 2014 2048-bit or longer keys will be required by <a target="_blank" href="https://www.cabforum.org/Baseline_Requirements_V1.pdf">Certification Authority/Browser Forum</a>.</li>
</ul>
<p>In addition, we need to supply information on the website URL, when the keytool asks for &#8220;What is your first and last name?&#8221;  The key and keystore passwords are optional.  This information and information on our institution have been highlighted in green in the example below.  </p>
<pre>$ sudo mkdir /etc/pki/tls/keystore
$ cd /etc/pki/tls/keystore
$ sudo keytool -genkey -alias <span style="color: blue">demo</span> -keyalg <span style="color: blue">RSA</span> -keystore <span style="color: blue">demo.colabrativ.com.jks</span> -keysize <span style="color: blue">2048</span>
Enter keystore password: <span style="color: #080; font-weight:600;">password</span>
Re-enter new password: <span style="color: #080; font-weight:600;">password</span>
What is your first and last name?
  [Unknown]:  <span style="color: #080; font-weight:600;">demo.colabrativ.com</span>
What is the name of your organizational unit?
  [Unknown]:  <span style="color: #080; font-weight:600;"></span>
What is the name of your organization?
  [Unknown]:  <span style="color: #080; font-weight:600;">Colabrativ, Inc.</span>
What is the name of your City or Locality?
  [Unknown]:  <span style="color: #080; font-weight:600;">Orinda</span>
What is the name of your State or Province?
  [Unknown]:  <span style="color: #080; font-weight:600;">California</span>
What is the two-letter country code for this unit?
  [Unknown]:  <span style="color: #080; font-weight:600;">US</span>
Is CN=demo.colabrativ.com, OU=Developmemt, O=Colabrativ, Inc., L=Orinda, ST=California, C=US correct?
  [no]:  <span style="color: #080; font-weight:600;">yes</span>

Enter key password for <demo>
        (RETURN if same as keystore password):

$ ls -lt
total 4
-rw-r--r-- 1 marc users 2246 Aug 30 08:53 demo.colabrativ.com.jks
</pre>
</div>
<h3 id="CSR-generation">Generating the Certificate Signing Request (CSR)</h3>
<div class="codeBox">
We need to supply the following: </p>
<ul>
<li><strong>alias</strong>: <span style="color: blue">demo</span></li>
<li><strong>keystore</strong> file name: <span style="color: blue">demo.colabrativ.com.jks</span></li>
<li>CSR <strong>file</strong> name: <span style="color: blue">demo.colabrativ.com.csr</span></li>
</ul>
<pre>$ keytool -certreq -alias <span style="color: blue">demo</span> -keystore <span style="color: blue">demo.colabrativ.com.jks</span> -file <span style="color: blue">demo.colabrativ.com.csr</span>
Enter keystore password: <span style="color: #080; font-weight:600;">password</span>

$ ls -lt
total 8
-rw-r--r-- 1 marc users 1039 Aug 30 08:55 demo.colabrativ.com.csr
-rw-r--r-- 1 marc users 2246 Aug 30 08:53 demo.colabrativ.com.jks
</pre>
</div>
<h3 id="check-CSR">Check the Certificate Signing Request (CSR)</h3>
<div class="codeBox">
Symantec Corporation provides a set of SSL tools at <a target="_blank" href="https://ssl-tools.verisign.com/#certChecker?sl=DENJS-0000-04-00">https://ssl-tools.verisign.com/#certChecker?sl=DENJS-0000-04-00</a>, including a CSR Validation.  After pasting your CSR into the window provided and running the validator, then following information on your CCR is shown: </p>
<table style="border:0px solid white;">
<tr>
<td>Common Name</td>
<td>demo.colabrativ.com</td>
</tr>
<tr>
<td>Organization</td>
<td>Colabrativ, Inc.</td>
</tr>
<tr>
<td>Organizational Unit</td>
<td>Unknown</td>
</tr>
<tr>
<td>Locality</td>
<td>Orinda</td>
</tr>
<tr>
<td>State</td>
<td>California</td>
</tr>
<tr>
<td>Country</td>
<td>US</td>
</tr>
<tr>
<td>Signature</td>
<td>Verified</td>
</tr>
<tr>
<td>Signature Algorithm </td>
<td>SHA1</td>
</tr>
<tr>
<td>Key Algorithm</td>
<td>RSA</td>
</tr>
<tr>
<td>Key Length</td>
<td>2048</td>
</tr>
</table>
<p>The signing request (demo.colabrativ.com.csr) can now be sent to the certificate authority.
</p></div>
<h3 id="loading-keystore">Loading the Certificates into the Java Keystore</h3>
<div class="codeBox">
After receiving the certificates from the certificate authority, they need to be loaded in the keystore before exporting the key.  You need both the certificate for your URL and the intermediate certificate from the certificate authority.  This example uses the following certificates and keystore:</p>
<ul>
<li><strong>intermediate certificate</strong> file name: <span style="color: blue">intermediate.crt</span></li>
<li><strong>certificate</strong> file name: <span style="color: blue">demo.colabrativ.com.crt</span></li>
<li><strong>keystore</strong> file name: <span style="color: blue">demo.colabrativ.com.jks</span></li>
</ul>
<p>First the certificate authorities intermediate certificate is loaded using the alias <span style="color: blue">root</span>.</p>
<pre>$ keytool -import -trustcacerts -alias <span style="color: blue">root</span> -file <span style="color: blue">intermediate.crt</span> -keystore <span style="color: blue">demo.colabrativ.com.jks</span>
Enter keystore password: <span style="color: #080; font-weight:600;">password</span>
Certificate was added to keystore
</pre>
<p>Then our certificate, <span style="color: blue">demo.colabrativ.com.crt</span> is loaded in the keystore using the alias <span style="color: blue">demo</span>.</p>
<pre>$ keytool -import -trustcacerts -alias <span style="color: blue">demo</span> -file <span style="color: blue">demo.colabrativ.com.crt</span> -keystore <span style="color: blue">demo.colabrativ.com.jks</span>
Enter keystore password: <span style="color: #080; font-weight:600;">password</span>
Certificate was added to keystore
</pre>
</div>
<h3 id="extract-key">Extracting the Key from the Keystore</a></h3>
<div class="codeBox">
<p>There are three steps in extracting the key from the keystore we created above:</p>
<ol>
<li>Use keytool to create an intermediate <span style="color: blue">PKCS12</span> keystore, <span style="color: blue">demo.colabrativ.com.pkcs12</span>, from the keystore, <span style="color: blue">demo.colabrativ.com.jks</span>.</li>
<li>Use OpenSSL to create a <a target="_blank" href="http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail">Privacy-enhanced Electronic Mail (PEM)</a> formatted file containing both the certificate and the key, <span style="color: blue">demo.colabrativ.com.pem</span>.
<li>Extract the key, <span style="color: blue">demo.colabrativ.com.key</span>, from the PEM file using a text editor.</li>
</ol>
<pre>$ sudo keytool -importkeystore -srckeystore <span style="color: blue">demo.colabrativ.com.jks</span> -destkeystore <span style="color: blue">demo.colabrativ.com.pkcs12</span> -deststoretype PKCS12
Enter destination keystore password: <span style="color: #080; font-weight:600;">password</span>
Re-enter new password: <span style="color: #080; font-weight:600;">password</span>
Enter source keystore password: <span style="color: #080; font-weight:600;">password</span>
Entry for alias tomcat successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

$ sudo openssl pkcs12 -in <span style="color: blue">demo.colabrativ.com.pkcs12</span> -out <span style="color: blue">demo.colabrativ.com.pem</span> -nodes
Enter Import Password: <span style="color: #080; font-weight:600;">password</span>
MAC verified OK

$ sudo cp demo.colabrativ.com.pem demo.colabrativ.com.key
$ sudo vi demo.colabrativ.com.key

$ ls -lt
total 20
-rw-r--r-- 1 marc users 1224 Aug 30 13:57 demo.colabrativ.com.key
-rw-r--r-- 1 marc users  509 Aug 30 13:53 demo.colabrativ.com.pem
-rw-r--r-- 1 marc users  509 Aug 30 13:50 demo.colabrativ.com.pkcs12
-rw-r--r-- 1 marc users 2246 Aug 30 13:48 demo.colabrativ.com.jks
-rw-r--r-- 1 marc users 1039 Aug 30 13:46 demo.colabrativ.com.crt
-rw-r--r-- 1 marc users 1039 Aug 30 13:45 intermediate.crt
-rw-r--r-- 1 marc users 1039 Aug 30 08:55 demo.colabrativ.com.csr
</pre>
<p>After the certificate and key have been prepared, they are moved the /etc/pki/tls/certs/, and /etc/pki/tls/private/ directories, respectively.</p>
<pre>
$ sudo mv intermediate.crt /etc/pki/tls/certs/.
$ sudo mv demo.colabrativ.com.crt /etc/pki/tls/certs/.
$ sudo mv demo.colabrativ.com.key /etc/pki/tls/private/.
</pre>
</div>
<h3 id="configure-ssl-conf">Configuring Apache Server (HTTPD) ssl.conf</h3>
<p>We will place all the SSL information for this server in the ssl.conf file in the /etc/httpd/conf.d directory.  The ssl.conf file is loaded into the Apache Server (HTTPD) from the command &#8220;include conf.d/*.conf&#8221; in httpd.conf in directory /etc/httpd/conf.  You should check to be sure that this command is in your httpd.conf file.</p>
<div class="codeBox">
Shown below are the differences between the original ssl.conf file and the edited version.  It is a bit hard to tell where these changes were made from the file differences, so a copy of a demonstration ssl.conf file can be downloaded at the bottom of the section.</p>
<pre>$ cd /etc/httpd/conf.d
$ sudo cp –p ssl.conf ssl.conf.orig
$ sudo vi ssl.conf
$ sudo diff ssl.conf.orig ssl.conf
19a20,21
&gt; NameVirtualHost *:443
&gt;
74c76,77
&gt; &lt;VirtualHost _default_:443&gt;
---
&gt; #&lt;VirtualHost _default_:443&gt;
&gt; &lt;VirtualHost *:443&gt;
78a82
&gt; ServerName demo.colabrativ.com:443
85a90,100
&gt; #
&gt; # Proxy Server directives. Uncomment the following lines to
&gt; # enable the proxy server:
&gt; #
&gt; ProxyRequests Off
&gt; ProxyPass        /admin   https://demo.colabrativ.com:8443/admin
&gt; ProxyPass        /demoapp https://demo.colabrativ.com:8443/demoapp
&gt;
&gt; SSLProxyEngine on
&gt;
105c120,121
&lt; SSLCertificateFile /etc/pki/tls/certs/localhost.crt
---
&gt; #SSLCertificateFile /etc/pki/tls/certs/localhost.crt
&gt; SSLCertificateFile /etc/pki/tls/certs/<span style="color: blue">demo.colabrativ.com.crt</span>
112c128,129
&lt; SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
---
&gt; #SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
&gt; SSLCertificateKeyFile /etc/pki/tls/private/<span style="color: blue">demo.colabrativ.com.key</span>
143c143
&lt; #SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
---
&gt; SSLCACertificateFile /etc/pki/tls/certs/<span style="color: blue">intermediate.crt</span>
</pre>
<p />
<p><strong>Download: <a target="_blank" href="http://www.colabrativ.com/files/demo_ssl.conf">demo_ssl.conf</a></strong></p>
</div>
<h3 id="add-keystore-to-tomcat">Adding Keystore to Tomcat&#8217;s server.xml</h3>
<div class="codeBox">
We configure Tomcat to support applications and services under the secure https protocol on port 8443.  We do this by editing the server.xml file in /etc/tomcat7.  We need to supply the keystore password in the 8443 Connector we enable.  I have saved the original server.xml, and only show the difference between the two files below. </p>
<pre>$ cd /etc/tomcat7
$ sudo cp -p server.xml server.xml.orig
$ sudo vi server.xml
$ sudo diff server.xml.orig server.xml
84,88c84,92
&lt;     &lt;!--
&lt;     &lt;Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
&lt;                maxThreads="150" scheme="https" secure="true"
&lt;                clientAuth="false" sslProtocol="TLS" /&#038;gt
&lt;     --&gt;
---
&gt;
&gt;     &lt;Connector port="8443"
&gt;                protocol="HTTP/1.1"
&gt;                SSLEnabled="true"
&gt;                maxThreads="150"
&gt;                scheme="https" secure="true"
&gt;                clientAuth="false" sslProtocol="TLS"
&gt;                keystoreFile="<span style="color: blue">/etc/pki/tls/keystore/demo.colabrativ.com.jks</span>"
&gt;                keystorePass="<span style="color: #080; font-weight:600;">password</span>" /&gt;
</pre>
</div>
<h3>Useful Resources</h3>
<ol>
<li>SSL Shopper&#8217;s <a target="_blank" href="http://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html">The Most Common Java Keytool Keystore Commands</a></li>
<li>SSL Shopper&#8217;s <a target="_blank" href="http://www.sslshopper.com/article-most-common-openssl-commands.html">The Most Common OpenSSL Commands</a></li>
<li>Wikipedia&#8217;s page on <a target="_blank" href="http://en.wikipedia.org/wiki/X.509">X.509</a>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/creating-ssl-certificates-for-google-web-toolkit-running-on-apache-httpd-and-tomcat-on-amazon-web-services-ec2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Todd Park&#8217;s Talk on Unleashing the Power of Open Data and Innovation for Health Care</title>
		<link>http://www.colabrativ.com/todd-park-talk-on-unleashing-the-power-of-open-data-and-innovation-for-health-care/</link>
		<comments>http://www.colabrativ.com/todd-park-talk-on-unleashing-the-power-of-open-data-and-innovation-for-health-care/#comments</comments>
		<pubDate>Thu, 27 Sep 2012 15:17:49 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Healthcare]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[Open Data]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=575</guid>
		<description><![CDATA[I had the chance to hear the rebroadcast of a talk by Todd Park, the U.S. Chief Technology Officer, given on June 18, 2012 at The Commonwealth Club of California, on Unleashing the Power of Open Data and Innovation for &#8230; <a href="http://www.colabrativ.com/todd-park-talk-on-unleashing-the-power-of-open-data-and-innovation-for-health-care/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I had the chance to hear the rebroadcast of a talk by Todd Park, the U.S. Chief Technology Officer, given on June 18, 2012 at The Commonwealth Club of California, on <a target="_Blank" href="http://www.commonwealthclub.org/events/2012-06-18/just-added-todd-park-us-chief-technology-officer">Unleashing the Power of Open Data and Innovation for Health Care.</a>  He is a leading proponent for open health data in the U.S. health system.  His team at Health and Human Services in collaboration with the <a target="_Blank" href="http://www.iom.edu/Activities/PublicHealth/HealthData.aspx">Institute of Medicine</a> launched the <a target="_Blank" href="http://healthdata.gov/">Health Data Initiative</a> in 2009.  This initiative follows in the footsteps of two other successful U.S. government open data projects.  40 year ago National Oceanic and Atmospheric Administration (NOAA) made weather data available for free public download.  In the 1980s, the U.S. government began making the Global Positioning System (GPS) available to the public.  </p>
<h3>Health Care Cost Reduction through Open Data</h3>
<p>The goal for this Health Data Initiative was to spur health care innovation that will drive down the cost of healthcare by allowing everyone to have access to health care information while <strong>protecting privacy and maintaining confidentiality of the information</strong>.  Mr. Park presented an example of how quickly such a scenario could come about.  In February of 2011, Georgetown hosted a hack-a-ton.  IN 8 hours, a group from Mia in Pittsburgh having no healthcare background, but with expertise in supply chain management built a working prototype of Food Oasis, an app to address the food desert problem.  If you live in a food desert, you do not have access to healthy food.  You can text a message to Food Oasis indicating the food you would like to purchase.  The message gets sent to a web site where farmers&#8217; markets and food coops can view the orders.  These suppliers then aggregate the data and find the orders they can fulfill.  They then text back to consumers when and where their orders can be picked up.  Due to the low overhead, this turns out to be a cost effective way of resolving this problem.  </p>
<h3>You Have the Right to Your Medical Records</h3>
<p><strong>You absolutely have the rights to your medical records.</strong>  In fact the head of the Department of Health and Human Services, check withing Todd for the name, has published an open letter stating that you have the rights to your own medical records. </p>
<h3>Information at HealthData.gov</h3>
<p>At <a target="_Blank" href="http://healthdata.gov/">healthdata.gov</a> you can find information on: </p>
<table style="border:0px solid white;">
<tr>
<td style="border:0px solid white; width:150px;">Administrative</td>
<td style="border:0px solid white;">Data on administering health care delivery, enrollment into health insurance plans and appeals.</td>
</tr>
<tr>
<td style="border:0px solid white;">Biomedical Research</td>
<td style="border:0px solid white;">Authoritative, up-to-date medical and scientific information resources for patients, families, health care providers and researchers.</td>
</tr>
<tr>
<td style="border:0px solid white;">Children&#8217;s Health</td>
<td style="border:0px solid white;">Information on children’s health and health-related services for researchers, policymakers, patients and families.</td>
</tr>
<tr>
<td style="border:0px solid white;">Epidemiology</td>
<td style="border:0px solid white;">Public health databases and registries regarding births, deaths, disease incidence, health event case reports, demographics, community health.</td>
</tr>
<tr>
<td style="border:0px solid white;">Health Care Cost</td>
<td style="border:0px solid white;">Includes National Health Expenditure Accounts (NHEA), the official estimates of total health care spending in the United States.</td>
</tr>
<tr>
<td style="border:0px solid white;">Health Care Providers</td>
<td style="border:0px solid white;">Freedom of Information Act disclosable health care provider data for providers.</td>
</tr>
<tr>
<td style="border:0px solid white;">Medicaid</td>
<td style="border:0px solid white;">General information on eligibility and claims data developed to support research and policy analysis initiatives for Medicaid recipients and other low-income populations.</td>
</tr>
<tr>
<td style="border:0px solid white;">Medicare</td>
<td style="border:0px solid white;">Cost report data from annual reports filed by hospitals, home health agencies, and other facilities; claim-level public use files for all major types of care.</td>
</tr>
<tr>
<td style="border:0px solid white;">Population Statistics</td>
<td style="border:0px solid white;">Metrics on community health, health care system, and determinants-of-health performance at national, state or county levels.</td>
</tr>
<tr>
<td style="border:0px solid white;">Quality Measurement</td>
<td style="border:0px solid white;">Quality and patient satisfaction data available via Application Programming Interfaces (APIs) for nursing homes, hospitals, home health agencies, and dialysis centers.</td>
</tr>
<tr>
<td style="border:0px solid white;">Safety</td>
<td style="border:0px solid white;">Includes all company-issued recalls for drugs, food, products from 2009 to the present; hazardous substances and environmental and public health maps.</td>
</tr>
<tr>
<td style="border:0px solid white;">Treatments</td>
<td style="border:0px solid white;">Information and databases about marketed drugs, including downloadable resources on medication content and labeling, text messaging libraries and product listing directories.</td>
</tr>
</table>
<p>I would encourage you to listen to the recording of Mr. Park&#8217;s talk on <a target="_Blank" href="http://www.commonwealthclub.org/events/2012-06-18/just-added-todd-park-us-chief-technology-officer">The Commonwealth Club of California</a> web site.  He covered many more health case related and open data topics during the hour he talked and answered audience questions. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/todd-park-talk-on-unleashing-the-power-of-open-data-and-innovation-for-health-care/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating Self-Signed Certificates for Google Web Toolkit Running on Apache HTTPD and Tomcat on Amazon Web Services EC2</title>
		<link>http://www.colabrativ.com/self-signed-certificates-gwt-applications-apache-http-tomcat/</link>
		<comments>http://www.colabrativ.com/self-signed-certificates-gwt-applications-apache-http-tomcat/#comments</comments>
		<pubDate>Mon, 27 Aug 2012 20:43:09 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Elastic Compute Cloud]]></category>
		<category><![CDATA[HTTP Server]]></category>
		<category><![CDATA[Tomcat]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=527</guid>
		<description><![CDATA[Creating and installing a self-signed Secure Sockets Layer (SSL) certificate on a server should be a relatively simple task. However, most of the documentation relating to these tasks is confusing. Most of the confusion arises from the fact that there &#8230; <a href="http://www.colabrativ.com/self-signed-certificates-gwt-applications-apache-http-tomcat/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Creating and installing a self-signed <a target="_blank" href="http://en.wikipedia.org/wiki/Secure_Sockets_Layer">Secure Sockets Layer (SSL)</a> certificate on a server should be a relatively simple task.  However, most of the documentation relating to these tasks is confusing.  Most of the confusion arises from the fact that there are a multitude of different server configurations that utilize the SSL to complete secure transactions over the web.  In order not to add to this confusion, the following tutorial will refer to the following server configuration: </p>
<table style="border:0px solid white;">
<tr>
<td style="border:0px solid white;">Server:</td>
<td style="border:0px solid white;">64 bit Linux server running on <a target="_blank" href="http://aws.amazon.com/">Amazon Web Services</a> <a target="_blank" href="http://aws.amazon.com/ec2/">Elastic Compute Cloud (EC2)</a> server based on AMI ami-3bc9997e</td>
</tr>
<tr>
<td style="border:0px solid white;">Server&nbsp;Software:</td>
<td style="border:0px solid white;"><a target="_blank" href="http://httpd.apache.org/ABOUT_APACHE.html">Apache HTTP Server (HTTPD)</a> and <a target="_blank" href="http://tomcat.apache.org/">Apache Tomcat</a></td>
</tr>
<tr>
<td style="border:0px solid white;">Applications&nbsp;Type:</td>
<td style="border:0px solid white;"><a target="_blank" href="https://developers.google.com/web-toolkit/">Google Web Toolkit</a> and Java servlets</td>
</tr>
</table>
<p>In this post I will describe:</p>
<ol>
<li><a href="#create-keystore">Creation of self-signed SSL certificate in a Java keystore</a></li>
<li><a href="#add-keystore-to-tomcat">Adding keystore to Tomcat&#8217;s server.xml</a></li>
<li><a href="#extract-key-cert">Extracting the certificate and the key from the keystore</a></li>
<li><a href="#configure-ssl-conf">Configuring Apache Server (httpd) ssl.conf</a></li>
</ol>
<h3 id="create-keystore">Creation of self-signed SSL certificate</h3>
<p>Here we will use a <a target="_blank" href="http://docs.oracle.com/javase/6/docs/api/java/security/KeyStore.html">Java KeyStore</a> to supply Apache Tomcat the certificates we generate.  One of the limitations to this approach is that you must start by creating the KeyStore first.  SSL utilities such as <a target="_blank" href="http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/keytool.html">Java keytool</a> and <a target="_blank" href="http://www.openssl.org/">OpenSSL</a> do not have the ability to create a keystore from an existing certificate and key.  In particular, there is no way to put the key in the keystore. </p>
<div class="codeBox">
<p>First we will create and open to the directory /etc/pki/tls/keystore.  The  <strong>keytool</strong> command that creates the keystore, we need to supply the following: </p>
<ul>
<li><strong>keystore</strong> file name: <span style="color: blue">demo.colabrativ.keystore</span></li>
<li><strong>alias</strong>: <span style="color: blue">tomcat</span></li>
<li><strong>keypass</strong>: <span style="color: blue">password</span></li>
<li><strong>storepass</strong>: <span style="color: blue">password</span></li>
</ul>
<p>In addition, we need to supply information on the website URL, when the keytool asks for &#8220;What is your first and last name?&#8221; and our institution information.  This information has been highlighted in green below in the example below.
</p>
<pre>$ sudo mkdir /etc/pki/tls/keystore
$ cd /etc/pki/tls/keystore
$ sudo keytool -genkey -alias tomcat -keypass <span style="color: blue">password</span> -keystore <span style="color: blue">demo.colabrativ.keystore</span> -storepass <span style="color: blue">password</span>
What is your first and last name?
  [Unknown]:  <span style="color: #080; font-weight:600;">demo.colabrativ.com</span>
What is the name of your organizational unit?
  [Unknown]:  <span style="color: #080; font-weight:600;">Developmemt</span>
What is the name of your organization?
  [Unknown]:  <span style="color: #080; font-weight:600;">Colabrativ, Inc.</span>
What is the name of your City or Locality?
  [Unknown]:  <span style="color: #080; font-weight:600;">El Sobrante</span>
What is the name of your State or Province?
  [Unknown]:  <span style="color: #080; font-weight:600;">California</span>
What is the two-letter country code for this unit?
  [Unknown]:  <span style="color: #080; font-weight:600;">US</span>
Is CN=demo.colabrativ.com, OU=Developmemt, O=Colabrativ, Inc., L=El Sobrante, ST=California, C=US correct?
  [no]:  <span style="color: #080; font-weight:600;">y</span>
</pre>
<p/>
<p>A useful command to check to keystore before preceeding is: </p>
<pre>$ sudo keytool -list -keystore <span style="color: blue">demo.colabrativ.keystore</span>
Enter keystore password: <span style="color: #080; font-weight:600;">password</span>

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

tomcat, Aug 27, 2012, PrivateKeyEntry,
Certificate fingerprint (MD5): 1A:2D:B5:C1:E9:1E:5C:A2:79:D3:8A:9B:A1:CE:14:72
</pre>
</div>
<h3 id="add-keystore-to-tomcat">Adding Keystore to Tomcat&#8217;s server.xml</h3>
<div class="codeBox">
<p>We configure Tomcat to support applications and services under the secure https protocol on port 8443.  We do this by editing the server.xml file in /etc/tomcat7.  We need to supply the keystore password in the 8443 Connector we enable.  I have saved the original server.xml, and only show the difference between the two files below. </p>
<pre>$ cd /etc/tomcat7
$ sudo cp -p server.xml server.xml.orig
$ sudo vi server.xml
$ sudo diff server.xml.orig server.xml
84,88c84,92
&lt;     &lt;!--
&lt;     &lt;Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
&lt;                maxThreads="150" scheme="https" secure="true"
&lt;                clientAuth="false" sslProtocol="TLS" /&#038;gt
&lt;     --&gt;
---
&gt;
&gt;     &lt;Connector port="8443"
&gt;                protocol="HTTP/1.1"
&gt;                SSLEnabled="true"
&gt;                maxThreads="150"
&gt;                scheme="https" secure="true"
&gt;                clientAuth="false" sslProtocol="TLS"
&gt;                keystoreFile="<span style="color: blue">/etc/pki/tls/keystore/demo.colabrativ.keystore</span>"
&gt;                keystorePass="<span style="color: blue">password</span>" /&gt;
</pre>
</div>
<h3 id="extract-key-cert">Extracting the Certificate and Key from the Keystore</a></h3>
<div class="codeBox">
<p>There are three steps in extracting the certificate and key from the keystore we created above:</p>
<ol>
<li>Use keytool to create an intermediate PKCS12 keystore.</li>
<li>Use OpenSSL to create a <a target="_blank" href="http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail">Privacy-enhanced Electronic Mail (PEM)</a> formatted file containing the certificate and the key.
<li>Extract the certificate and key from the PEM file using a text editor.</li>
</ol>
<p>After the certificate and key have been prepared, they are moved the /etc/pki/tls/certs/, and /etc/pki/tls/private/ directories, respectively.
<p>The ASCII demo.colabrativ.pem file created during the preparation of this tutorial can be download at the bottom of this section. </p>
<pre>$ sudo keytool -importkeystore -srckeystore <span style="color: blue">demo.colabrativ.keystore</span> -destkeystore <span style="color: blue">demo.colabrativ.intermediate</span> -deststoretype PKCS12
Enter destination keystore password: <span style="color: #080; font-weight:600;">password</span>
Re-enter new password: <span style="color: #080; font-weight:600;">password</span>
Enter source keystore password: <span style="color: #080; font-weight:600;">password</span>
Entry for alias tomcat successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

$ sudo openssl pkcs12 -in <span style="color: blue">demo.colabrativ.intermediate</span> -out <span style="color: blue">demo..colabrativ.pem</span> -nodes
Enter Import Password: <span style="color: #080; font-weight:600;">password</span>
MAC verified OK

$ sudo cp demo.colabrativ.pem demo.colabrativ.key
$ sudo cp demo.colabrativ.pem demo.colabrativ.crt
$ sudo vi demo.colabrativ.key
$ sudo vi demo.colabrativ.crt

$ ls -lt
total 20
-rw-r--r-- 1 root root 1224 Aug 27 10:11 demo.colabrativ.crt
-rw-r--r-- 1 root root  509 Aug 27 10:11 demo.colabrativ.key
-rw-r--r-- 1 root root 2294 Aug 27 10:02 demo.colabrativ.pem
-rw-r--r-- 1 root root 1852 Aug 27 10:00 demo.colabrativ.intermediate
-rw-r--r-- 1 root root 1333 Aug 27 09:37 demo.colabrativ.keystore

$ sudo mv demo.colabrativ.crt /etc/pki/tls/certs/.
$ sudo mv demo.colabrativ.key /etc/pki/tls/private/.
</pre>
</p>
<p><strong>Download: <a target="_blank" href="http://www.colabrativ.com/files/ssl.conf">demo.colabrativ.pem</a></strong>
</div>
<h3 id="configure-ssl-conf">Configuring Apache Server (HTTPD) ssl.conf</a></h3>
<p>We will place all the SSL information for this server in the ssl.conf file in the /etc/httpd/conf.d directory.  The ssl.conf file is loaded into the Apache Server (HTTPD) from the command &#8220;Include conf.d/*.conf&#8221; in httpd.conf in directory /etc/httpd/conf.  You should check to be sure that this command is in your httpd.conf file.</p>
<div class="codeBox">
<p>We will place all the SSL information for this server in the ssl.conf file in the /etc/httpd/conf.d directory.  Shown below are the differences between the original ssl.conf file and the edited version.  It is a bit hard to tell where these changes were made from the file differences, so a copy of a demonstration ssl.conf file can be downloaded at the bottom of the section.</p>
<pre>$ cd /etc/httpd/conf.d
$ sudo cp –p ssl.conf ssl.conf.orig
$ sudo vi ssl.conf
$ sudo diff ssl.conf.orig ssl.conf
19a20,21
&gt; NameVirtualHost *:443
&gt;
74c76,77
&gt; &lt;VirtualHost _default_:443&gt;
---
&gt; #&lt;VirtualHost _default_:443&gt;
&gt; &lt;VirtualHost *:443&gt;
78a82
&gt; ServerName demo.colabrativ.com:443
85a90,100
&gt; #
&gt; # Proxy Server directives. Uncomment the following lines to
&gt; # enable the proxy server:
&gt; #
&gt; ProxyRequests Off
&gt; ProxyPass        /admin   https://demo.colabrativ.com:8443/admin
&gt; ProxyPass        /demoapp https://demo.colabrativ.com:8443/demoapp
&gt;
&gt; SSLProxyEngine on
&gt;
105c120,121
&lt; SSLCertificateFile /etc/pki/tls/certs/localhost.crt
---
&gt; #SSLCertificateFile /etc/pki/tls/certs/localhost.crt
&gt; SSLCertificateFile /etc/pki/tls/certs/demo.colabrativ.crt
112c128,129
&lt; SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
---
&gt; #SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
&gt; SSLCertificateKeyFile /etc/pki/tls/private/demo.colabrativ.key
</pre>
<p />
<p><strong>Download: <a target="_blank" href="http://www.colabrativ.com/files/ssl.conf">ssl.conf</a></strong></p>
</div>
<h3>Useful Resources</h3>
<ol>
<li>SSL Shopper&#8217;s <a target="_blank" href="http://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html">The Most Common Java Keytool Keystore Commands</a></li>
<li>SSL Shopper&#8217;s <a target="_blank" href="http://www.sslshopper.com/article-most-common-openssl-commands.html">The Most Common OpenSSL Commands</a></li>
<li>Wikipedia&#8217;s page on <a target="_blank" href="http://en.wikipedia.org/wiki/X.509">X.509</a>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/self-signed-certificates-gwt-applications-apache-http-tomcat/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>File Drag and Drop onto a Google Web Toolkit Application</title>
		<link>http://www.colabrativ.com/file-drag-and-drop-onto-a-google-web-toolkit-application/</link>
		<comments>http://www.colabrativ.com/file-drag-and-drop-onto-a-google-web-toolkit-application/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 03:29:31 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[drag & drop]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[iExperiment]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[XMLSttpRequest]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=316</guid>
		<description><![CDATA[Users increasingly expect to be able to drag and drop objects in applications, including web applications. I would like to show you how we recently added the ability to drop files on to our enterprise electronic notebook iExperiment. iExperiment&#8217;s client &#8230; <a href="http://www.colabrativ.com/file-drag-and-drop-onto-a-google-web-toolkit-application/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Users increasingly expect to be able to drag and drop objects in applications, including web applications.  I would like to show you how we recently added the ability to drop files on to our enterprise electronic notebook iExperiment. iExperiment&#8217;s client side is built on Google Web Toolkit (GWT).  GWT currently does not support file drag and drop. </p>
<p>The work flow for file drag and drop is as follows: </p>
<ol>
<li>The user drops a file on to the client.</li>
<li>The client sends the drop element id and the file to the server in a multipart POST for storage and analysis.</li>
<li>The server sends back the POST response to the client with information on how to display the dropped file.</li>
<li>The client presents the uploaded file&#8217;s information to the user.</li>
</ol>
<p>We are using cutting edge HTML5 APIs in our drag and drop implementation.  Support of these APIs is not available in all browsers. </p>
<ul>
<li>This code works today in recent versions of Chrome and FireFox. </li>
<li>In Safari there is an issue with extra characters being added to the file names, which also complicates the file type assignment. </li>
<li>Internet Explorer does not currently support the required APIs. </li>
</ul>
<p>The file drop event is handled by adding an &#8220;ondrop&#8221; attribute to the HTML elements.  The &#8220;ondrop&#8221; attribute calls the droppedFile JavasScript routine that creates and sends an HTTP POST request to the server.  Note that the first argument in the droppedFile JavaScript call is an &#8220;element-id&#8221;, and the event is the second argument.  The drop element ID allows us to identify where the file was dropped on the page.</p>
<div class="codeBox">
  <strong>Example of &#8220;ondrop&#8221; Attribute in an HTML Table Element</strong></p>
<pre>&lt;table ondrop="event.stopPropagation();
               event.preventDefault();
               droppedFile('element-id', event);"&gt;</pre>
</div>
<p>The &#8220;ondrop&#8221; element is created by the static addOnDrop method in a client side class (DropFileConnector). </p>
<div class="codeBox">
  <strong>addOnDrop Method</strong></p>
<pre>/** Add an ondrop attribute to an element in the DOM, for example:
 * ondrop="event.stopPropagation(); droppedFile('element-id', event);"
 *
 * @param element DOM element
 * @param elementID Element Id to be sent to droppedFile routine.
 */
 public static void addOnDrop(Element element, String elementID) {
     element.setAttribute("ondrop",
         "event.stopPropagation(); droppedFile(\'" + elementID + "\', event);");
 }</pre>
</div>
<p>The droppedFile JavaScript routine creates a FormData element which is transferred to the server using a multipart HTTP POST request.  The first two items appended to the form are the drop element ID (dropElementID) and boundary that is used by the request onreadystatechange function.  Two appends are made to the form for each file that is uploaded; the file length (line 16), and the file itself (line 17) are appended to the form.  On lines 20-24 the information needed for the POST is created, and the upload handlers are attached to the request.  Note that by using a FormData element we are able to eliminate the deprecated FireFox specific methods <code>files[i].getAsBinary()</code>, and replace <code>request.sendAsBinary(postContent)</code> with request.send(formData).  These methods were used in our <a target="_blank" href=""http://www.colabrativ.com/drag-and-drop-onto-a-google-web-toolkit-application-utdated">original post</a> to added the files to the POST, and to send the POST, respectively. </p>
<p>The POST responses are handled by the request.onreadystatechange function on line 26-40, and are sent to the client through <code>window.top.dropFileListener.droppedFile method</code> (calls on lines 34 and 38.)  Initially when the read state is 1 (<code>readyState == 1</code>) the file name and the MIME boundary are sent to GWT client application on lines 28-35.  After succesful completion of the POST (<code>readyState == 4</code>), the POST response is forwarded to the GWT client application.</p>
<div class="codeBox">
  <strong>droppedFile JavaScript Routine</strong></p>
<pre>01  var boundary = null;
02
03  function droppedFile(dropElementID, event) {
04      if (window.File &amp;&amp; window.FileList &amp;&amp; window.top.dropFileListener) {
05          if (event.dataTransfer) {
06              url = secureURL + "upload";
07              boundary = "Colabrativ-" + Math.floor(999999999999999 * Math.random());
08
09              var formData = new FormData();
10              formData.append("drop-element-id", dropElementID);
11              formData.append("boundary", boundary);
12
13              var files = event.dataTransfer.files;
14
15              for (var i = 0; i < files.length; i++) {
16                  formData.append("file-length-" + i, files[i].size);
17                  formData.append("file-"        + i, files[i]);
18              }
19
20              var request = new XMLHttpRequest();
21              request.upload.onprogress = updateProgress;
22              request.upload.onload     = loaded;
23              request.upload.onerror    = loadError;
24              request.open("POST", url, true);
25
26              request.onreadystatechange = function() {
27                  if (this.readyState == 1) {
28                      var filesJSON = '"files":[';
29                      for (var i = 0; i < files.length; i++) {
30                          filesJSON = filesJSON + '"' + files[i].name + '"';
31                          if (i < files.length - 1) filesJSON = filesJSON + ', ';
32                      }
33                      filesJSON = filesJSON + ']'
34                      window.top.dropFileListener.droppedFile( '{' +
35                          '"requestBoundary": "' + boundary + '", ' + filesJSON + '}');
36                  }
37                  if (this.readyState == 4) {
38                     window.top.dropFileListener.droppedFile( request.responseText );
39                  }
40              }
41
42              request.send(formData);
43          }
44          else {
45              alert("Your browser does not support file drag and drop.  " +
46                    "We recommend that you upgrade your browser to one that supports HTML5, " +
47                    "such as Mozilla's FireFox or Google's Chrome.");
48          }
49      }
50      else {
51          alert("window.top.dropFileListener not found!");
52      }
53  }</pre>
</div>
<p>The DropFileConnector class connects the dropFileListener in the JavaScript to the GWT code.  The DropFileConnector class has a ClientSideDropFileSupport interface that defines the droppedFile method in the JavaScript.  The observer (theObserver) is a static ClientSideDropFileSupport incidence that connects to the JavaScript droppedFile method to ClientSideDropFile&#8217;s droppedFile method. </p>
<div class="codeBox">
  <strong>DropFileConnector class</strong></p>
<pre>package com.colabrativ.common.client; 

import com.google.gwt.dom.client.Element; 

public class DropFileConnector {
    /** Used to pass information to the GWT application. Register your implementations with
      *  {@link com.colabrativ.common.client.DropFileConnector#connect( ClientSideDropFileSupport)}
      */
    public interface ClientSideDropFileSupport {
        /** The page calls this method to send dropped file information to application
          *
          * @param json JSON string containing the file name information.
          */
        void droppedFile(String json);
    } 

    /** An observer of drop file events, supplied by the GWT application. */
    static private ClientSideDropFileSupport theObserver; 

    /**
      * Connect the GWT application to the drop file JavaScript. The observer is notified
      * whenever the user drops a file on the application area (id="app-area").
      *
      * @param observer
      */
     public static void connect( ClientSideDropFileSupport observer ) {
         theObserver = observer;
         connectToPanel();
     }

     // These methods are "glue" methods that let the simple JNDI call talk to the observer through its interface.
     @SuppressWarnings("all")
     private static void droppedFile(String s) { theObserver.droppedFile(s); }

     private static native void connectToPanel() /*-{
         var listener = new Object();
         listener.droppedFile = function(json) {
             json = unescape( json );
             @com.colabrativ.common.client.DropFileConnector::droppedFile( Ljava/lang/String;)( json );
         };

         $wnd.top.dropFileListener = listener;
     }-*/; 

     /**
       * Add an ondrop attribute to an element in the DOM, for example:
       * ondrop="event.stopPropagation(); droppedFile('element-id', event);"
       *
       * @param element DOM element
       * @param elementId Element Id to be sent to droppedFile routine.
       */
      public static void addOnDrop(Element element, String elementId) {
          element.setAttribute("ondrop",
              "event.stopPropagation(); droppedFile(\'" + elementId + "\', event);");
      }
} </pre>
</div>
<p>Finally, a <code>DropFileConnector.connect</code> call is made in a client class that handles the POST responses.  Our upload servlet adds either an OKAY or a FAIL to the POST response that the DropFileConnector handles.  In our implementation, the POST responses are encapsulated in JSON.  The upload progress monitoring is also handled by the DropFileConnector.  In our implementation, the MIME boundary is used as an Id for the upload, and the monitoring is managed by the singleton of the UploadManager class. </p>
<div class="codeBox">
  <strong>DropFileConnector Connection</strong></p>
<pre>DropFileConnector.connect(
    new DropFileConnector.ClientSideDropFileSupport() {
        public void droppedFile(String response) {
            if (response.startsWith("OKAY:")) {
                String json = response.substring( response.indexOf(": ") + 2); // Remove OKAY:
                determineWhatToDoWithResponse(json);
            }
            else if (response.startsWith("FAIL:")) {
                // Do Nothing?
            }
            else {
                JSONObject responseJSON = (JSONObject) JSONParser.parseStrict( response );
                JSONString boundaryJSON = (JSONString) responseJSON.get( UploadResponse.requestBoundary);

                if (boundaryJSON != null) {
                    String boundary = boundaryJSON.toString();
                    JSONArray filesJSON = (JSONArray) responseJSON.get( UploadResponse.files);

                    if (filesJSON != null) {
                        UploadManager.getInstance().addProgressDialog( boundary, filesJSON);
                    }
                    else {
                        UploadManager.getInstance().update( boundary, responseJSON);
                    }
                }
            }
        }
    }
); </pre>
</div>
<p>Several resources helped us create our file drag and drop; these included: </p>
<ol>
<li>W3C XMLHttpRequest Level 2 <a target="_blank" href="http://www.w3.org/TR/XMLHttpRequest2/">http://www.w3.org/TR/XMLHttpRequest2/</a></li>
<li>W3C File API <a target="_blank" href="http://www.w3.org/TR/file-upload/">http://www.w3.org/TR/file-upload/</a></li>
<li>Using FormData object in Mozilla&#8217;s Developers Network page on Using XMLHttpRequest at <a target="_blank" href="https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Using_FormData_objects">https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Using_FormData_objects</a></li>
<li>How to Use HTML5 File Drag &amp; Drop by Craig Buckler at <a target="_blank" href="http://www.sitepoint.com/html5-file-drag-and-drop/">http://www.sitepoint.com/html5-file-drag-and-drop/</a></li>
<li>XHR progress and rich file upload feedback by Austin King at <a target="_blank" href="http://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/">http://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/file-drag-and-drop-onto-a-google-web-toolkit-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation of Test Patients Table in Microsoft Excel</title>
		<link>http://www.colabrativ.com/creation-of-test-patients-table-in-microsoft-excel/</link>
		<comments>http://www.colabrativ.com/creation-of-test-patients-table-in-microsoft-excel/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 18:28:58 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[patients]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=260</guid>
		<description><![CDATA[We are helping Deb Zajchowski at The Clearity Foundation on their patient database. The Clearity Foundation is a non-profit organization dedicated to &#34;improving treatment options for ovarian cancer patients.&#34; To improve treatment they take a personalized medicine approach. They have &#8230; <a href="http://www.colabrativ.com/creation-of-test-patients-table-in-microsoft-excel/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We are helping Deb Zajchowski at <a target="_blank" href="http://www.clearityfoundation.org/default.aspx">The Clearity Foundation</a> on their patient database. The Clearity Foundation is a non-profit organization dedicated to &quot;improving treatment options for ovarian cancer patients.&quot; To improve treatment they take a personalized medicine approach.  They have a privacy-ensured database in which they collect information on the patient’s clinical history, including physician’s diagnosis, diagnostic procedures, treatments and the results from tumor molecular profiling analyses.  The database also records the drugs that are likely to have clinical benefit based on the profile of the patient’s cancer. </p>
<p>Our goal is to enhance the Clearity database ability to track the patient outcomes in a retrospective analysis.  The current database was developed by Michael L. Petka.  It works well for the profiling and reporting needs of the organization.  However, Mike is currently occupied with other aspects of database enhancement. </p>
<p>In order to ensure the privacy of the patient, we needed a test database that did not contain any actual patient information. In this blog I will describe how we created a test Patients table in Excel. </p>
<p>The Patients table was created by Michael L. Petka, and is made up of the following columns:</p>
<table>
<thead>
<caption><strong>Patients Table Columns</strong></caption>
<tr>
<th>Column Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>PatientID</td>
<td>Patient Identification Key</td>
</tr>
<tr>
<td>PatientLastName</td>
<td>Last Name</td>
</tr>
<tr>
<td>PatientFirstName</td>
<td>First Name</td>
</tr>
<tr>
<td>PatientMiddleInitial</td>
<td>Middle Initial</td>
</tr>
<tr>
<td>PatAddress</td>
<td>Street Address</td>
</tr>
<tr>
<td>PatCity</td>
<td>City</td>
</tr>
<tr>
<td>PatState</td>
<td>State</td>
</tr>
<tr>
<td>PatZip</td>
<td>5-digit ZIP Code</td>
</tr>
<tr>
<td>SSN</td>
<td>Social Security Number</td>
</tr>
<tr>
<td>DOB</td>
<td>Date of Birth</td>
</tr>
<tr>
<td>Sex</td>
<td>Sex</td>
</tr>
<tr>
<td>PatientTelephoneNumber</td>
<td>Telephone Number</td>
</tr>
<tr>
<td>PatientEmail</td>
<td>Patient Email</td>
</tr>
</tbody>
</table>
<h3>Patient Identification Key</h3>
<p>The patient identification key (PatientID) is a sequential numbering of the patient rows.                </p>
<h3>Patient Name</h3>
<p>We were fortunate to find a table of 10,000 random names at <a target="_blank" href="http://www.opensourcecf.com/1/2009/05/10000-Random-Names-Database.cfm">The ColdFusion Open Source Software Blog.</a>  In addition to the columns we needed, this database has complete name strings, both first name first, and last name first. The first name, last name and middle initial columns were cut and pasted into our test Patients table in Excel. </p>
<h3>Patient Sex</h3>
<p>The sex of the random names was determined in Excel by comparing the first name of a random name with a list of girls&#8217; names from <a target="_blank" href="http://www.randomnames.com/allnames.asp?g=f">RandomNames.com</a>.  If the name matched, F (female) was assigned, otherwise M (male) was assigned, using the function below.</p>
<div class="codeBox">
<p><strong>Sex Determination Based on Name</strong></p>
<pre>=IF(EXACT(A5,LOOKUP(A5,I$2:I$895)),"F","M")</pre>
<p>where column A contains the random first name (above element A5 is being examined), and array I2 to I895 contains the girls&#8217; first names.</p>
</div>
<h3>Street Address</h3>
<p>We found 261 of the most popular neighborhood street names at <a target="_blank" href="http://www.livingplaces.com/streets/most-popular_street_names.html">Living Places</a>.  We generated random house numbers and random street names, then concatenated them together in Excel.</p>
<div class="codeBox">
<p><strong>Random House Number</strong></p>
<pre>=INT(11000*RAND())</pre>
<p><strong>Random Street Name</strong></p>
<pre>=INDIRECT("StreetNames!B"&amp;RANDBETWEEN(2,262))</pre>
<p>where array B2 to B262 in the StreetNames worksheet contains the most-popular neighborhood street names. </p>
<p><strong>Street Address Concatenation</strong></p>
<pre>=CONCATENATE(A5," ", B5)</pre>
<p>In the example above we are working on row 5, where column A contains the random house number and column B contains the random street name.</p>
</div>
<h3>City, State and ZIP code</h3>
<p>A table containing city, state and ZIP codes of 80,810 places was downloaded from <a target="_blank" href="http://federalgovernmentzipcodes.us/">A Free Zip Code Database</a> as the Excel file <a href="http://federalgovernmentzipcodes.us/free-zipcode-database.xlsx">free-zipcode-database.xlsx</a>.  This file has more than just city, state and ZIP codes.  It also includes type (STANDARD, PO BOX ONLY, MILITARY, etc.), county name, latitude, longitude, population, land area and water area.  In Excel, the table was sorted on type, for we only wanted to use types STANDARD and PO BOX ONLY.  After removing everything else, the list was reduced from 80,180 to 73,756 entries.  We then generated 10,000 random ZIP keys to match up with our 10,000 random names in Excel using RANDBETWEEN(2,73757).  All of this was stored in the City worksheet in Excel.  In the Patients table (worksheet), the city, state and ZIP codes were added using arandom ZIP code key.  The city name was capitalized using the PROPER function; see below. </p>
<div class="codeBox">
<p><strong>City, State and ZIP Code</strong></p>
<pre>=PROPER(INDIRECT("City!D"&amp;City!M5))

=INDIRECT("City!E"&amp;City!M5))

=INDIRECT("City!A"&amp;City!M5))</pre>
<p>Where &#8220;City!D&#8221;, &#8220;City!E&#8221; and &#8220;City!A&#8221; are the city, state and ZIP code columns, respectively, in the City worksheet. </p>
</div>
<h3>Social Security Number</h3>
<p>A random social security number (SSN) was generated for each fictitious patient by concatenating three RANDBETWEEN operations together; see below.</p>
<div class="codeBox">
<p><strong>Social Security Number</strong></p>
<pre>=CONCATENATE(RANDBETWEEN(100,999),"-",RANDBETWEEN(10,99),"-",MID((RANDBETWEEN(10000,19999)),2,4))</pre>
</div>
<h3>Date of Birth</h3>
<p>We wanted a normal distribution of birthdays, so we randomly seeded the NORMINV function with random value between 0 and 1.  We used a mean of 21,000 (June 29, 1957) and a standard deviation of 5,000 days (13.7 years) in the NORMINV function to get an acceptable distribution; see below.</p>
<div class="codeBox">
<p><strong>Normally Distributed Date of Birth</strong></p>
<pre>=NORMINV(RAND(),21000,5000)</pre>
</div>
<h3>Telephone Number</h3>
<p>Random telephone numbers were generated in the same manner as the social security numbers, by concatenation of three RANDBETWEEN operations; see below.</p>
<div class="codeBox">
<p><strong>Telephone Number</strong></p>
<pre>=CONCATENATE(INT(RANDBETWEEN(100,999)),"-",INT(RANDBETWEEN(100,999)),"-",MID((RANDBETWEEN(10000,19999)),2,4))</pre>
</div>
<h3>Email Address</h3>
<p>Fictitious patient email addresses were constructed from each fictitious patient&#8217;s first name, last name and the domain name &#8220;@example.com&#8221;; see below.</p>
<div class="codeBox">
<p><strong>Email Address</strong></p>
<pre>=CONCATENATE(C5,".",B5,"@example.com")</pre>
<p>where columns B and C contain the last and first names, respectively.  In the example above we are working on row 5.</p>
</div>
<h3>Stability of the Excel Random Cells</h3>
<p>We found that the randomly created cells in Excel were not stable.  If such a cell were edited, previous random values would be regenerated, effecting all the cell that depended on that random number.  Therefore, the final step was to write out the Patients worksheet as a comma-separated values (CSV) file, and then to read the CSV back into Excel.  In this way we were able to create a stable test Patients table in Excel.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/creation-of-test-patients-table-in-microsoft-excel/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Setup of iExperiment on Amazon&#8217;s Elastic Compute Cloud (EC2) Server</title>
		<link>http://www.colabrativ.com/setup-of-iexperiment-on-amazons-elastic-compute-cloud-ec2-server/</link>
		<comments>http://www.colabrativ.com/setup-of-iexperiment-on-amazons-elastic-compute-cloud-ec2-server/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 05:27:56 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Elastic Compute Cloud]]></category>
		<category><![CDATA[iExperiment]]></category>
		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=246</guid>
		<description><![CDATA[A research organization&#8217;s experiment records are the foundation of its intellectual property, and, as such, must be stored in a way that allows the research organization to maintain control over these records. Enterprise electronic notebooks, such as our iExperiment, store &#8230; <a href="http://www.colabrativ.com/setup-of-iexperiment-on-amazons-elastic-compute-cloud-ec2-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A research organization&#8217;s experiment records are the foundation of its intellectual property, and, as such, must be stored in a way that allows the research organization to maintain control over these records.  Enterprise electronic notebooks, such as our iExperiment, store their experiment records on a server.  Many organizations, including Colabrativ, Inc., are using cloud computing to lower the cost of a server and IT costs in general.  Amazon&#8217;s <a target="_blank" href="http://aws.amazon.com/ec2/">Elastic Compute Cloud (EC2)</a> is one of the lower cost cloud service providers.  Amazon is <a target="_blank" href="http://sas70.com/sas70_overview.html">Statement on Auditing Standards No. 70 (SAS70)</a> compliant.  They completed the Type II audit in 2009 (see <a target="_blank" href="http://aws.amazon.com/about-aws/whats-new/2009/11/11/aws-completes-sas70-type-ii-audit/">AWS Completes SAS70 Type II Audit</a> announcement).  Thus, one can be comfortable that they are doing everything they can to keep one&#8217;s data secure.  Amazon Web Services places the responsibility of the enterprise application setup and maintenance on the client&#8217;s administrator.  Other full-service SAS70-compliant cloud service providers will happily take on these responsibilities for you, for a fee. </p>
<p>In my previous post, I described the <a traget="_blank" href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment">Setup of Amazon&#8217;s Elastic Compute Cloud (EC2) Server for iExperiment</a>, our enterprise electronic notebook application.  That post covered the following topics:</p>
<ul>
<li><a href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment#requirements">iExperiment Server Requirements</a></li>
<li><a href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment#ec2-instance-setup">Setup of Amazon Web Services EC2 Instance</a></li>
<li><a href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment#attaching-ebs">Creating and Attaching an Elastic Block Storage Volume (optional)</a></li>
<li><a href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment#dns-server">Assigning URL of the iExperiment EC2 Server on the DNS Server</a></li>
</ul>
<p>You may want to take a quick look at <a href="./setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment#requirements">iExperiment Server Requirements</a>. </p>
<p>In this post we will go over the setup and configuration of the EC2 server and the installation and setup of iExperiment on it.  Topics in this post include: </p>
<ul>
<li><a href="#update-server">Updating the EC2 Server</a></li>
<li><a href="#mounting-ebs">Mounting Elastic Block Storage Volume (optional)</a></li>
<li><a href="#installing-MySQL">Installing MySQL</a></li>
<li><a href="#database-setup">iExperiment Database Setup</a></li>
<li><a href="#SSL-certificate">SSL Certificate Creation</a></li>
<li><a href="#apache-tomcat">Set Up of Apache and Tomcat</a></li>
<li><a href="#index-html">Adding index.html</a></li>
<li><a href="#iExperiment-applications">iExperiment Applications Installation</a></li>
<li><a href="#removing-8443">Removing Port 8443 from HTTPS Requests</a></li>
</ul>
<p>The majority of these tasks are preformed on the iExperiment EC2.  Tests of the server&#8217;s operation were made using Firefox 5.  We use <a target="_blank" href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">PuTTY</a> to log onto our EC2 server (Instructions can be found in an Amazon appendix on <a target="_blank" href="http://docs.amazonwebservices.com/AmazonEC2/gsg/2007-01-19/putty.html">PuTTY</a>. </p>
<div class="codeBox">
<h3 id="update-server">Updating the EC2 Server using Amazon&#8217;s Yum repository</h3>
<p>The update of the EC2 server from Amazon&#8217;s <a target="_blank" href="http://yum.baseurl.org/">Yum</a> repository takes only a single command &#8220;sudo yum update&#8221;.  It produces a large output.  During the update you will be asked two yes-no question.  You should answer &#8220;yes&#8221; to both of these questions.  Below I have edited the session to only include the yum command and text around the two questions.</p>
<pre>> sudo yum update
...
===============================================================================
Install       1 Package(s)
Upgrade      47 Package(s)

Total download size: 113 M
Is this ok [y/N]: Y
...
Importing GPG key 0x21C0F39F "Amazon Linux AMI (Beta)
<linux-security@amazon.com>" from /etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-beta
Is this ok [y/N]: Y
</pre>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="mounting-ebs">Mounting Elastic Block Storage Volume (optional)</h3>
<p>In order to format the elastic block storage (EBS) volume, we need to install XFS filesystem utilities (xfsprogs) from the Amazon Yum repository.</p>
<p>The /proc/partitions file contains a list of the volumes associated with the EC2 instance.  The /dev/xvda1 device is the system volume.  The other volume is the unformatted EBS volume we associated with the EC2 instance.  The EBS volume has two related device names; the system refers to the device as dev/xvd[f-p], but mkds.xfs takes /dev/sd[f-p].  In the case below, the device names are /dev/xsdf and /dev/sdf, respectively. </p>
<ol>
<li>Format the EBS volume using mkfs.xfs and the device name (/dev/sdf)</li>
<li>Create a mount point for the volume (/ebs1).</li>
<li>Add the mount point to the /etc/fstab file.</li>
<li>Mount the volume. </li>
</ol>
<pre>> sudo yum install xfsprogs
Is this ok [y/N]: y

> more /proc/partitions
major  minor  #blocks  name
 202        1    8388608 xvda1
 202       80   10485760 xvdf

> sudo mkfs.xfs /dev/sdf
meta-data=/dev/sdf               isize=256    agcount=4, agsize=65536 blks
         =                       sectsz=512   attr=2
data     =                       bsize=4096   blocks=2621440, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0sudo vi /etc/fstab

> sudo mkdir /ebs1

> sudo cp -p /etc/fstab /etc/fstab.orig
> sudo vi /etc/fstab
> more /etc/fstab
#
LABEL=/     /           ext4    defaults,noatime  1   1
tmpfs       /dev/shm    tmpfs   defaults        0   0
devpts      /dev/pts    devpts  gid=5,mode=620  0   0
sysfs       /sys        sysfs   defaults        0   0
proc        /proc       proc    defaults        0   0
/dev/xvdf   /ebs1       xfs     noatime         0   0

> sudo mount /ebs1
</pre>
<p>After mounting the EBS volume on /ebs1, we create and link both the iExperiment and MySQL directories.  We add the mounts to the /etc/fstab file, then mount the directories.</p>
<pre>> sudo mkdir /ebs1/etc
> sudo mkdir /ebs1/etc/mysql
> sudo mkdir /ebs1/lib
> sudo mkdir /ebs1/lib/mysql
> sudo mkdir /ebs1/log
> sudo mkdir /ebs1/log/mysql
> sudo mkdir /ebs1/log/iexperiment
> sudo mkdir /ebs1/local/iexperiment

> sudo mkdir /etc/mysql
> sudo mkdir /var/lib/mysql
> sudo mkdir /var/log/mysql
> sudo mkdir /var/log/iexperiment
> sudo mkdir /var/local/iexperiment

> sudo vi /etc/fstab
> more /etc/fstab
#
LABEL=/     /           ext4    defaults,noatime  1   1
tmpfs       /dev/shm    tmpfs   defaults        0   0
devpts      /dev/pts    devpts  gid=5,mode=620  0   0
sysfs       /sys        sysfs   defaults        0   0
proc        /proc       proc    defaults        0   0
/dev/xvdf   /ebs1       xfs     noatime         0   0
/ebs1/etc/mysql          /etc/mysql              none    bind
/ebs1/lib/mysql          /var/lib/mysql          none    bind
/ebs1/log/mysql          /var/log/mysql          none    bind
/ebs1/log/iexperiment    /var/log/iexperiment    none    bind
/ebs1/local/iexperiment  /var/local/iexperiment  none    bind

> sudo mount /etc/mysql
> sudo mount /var/lib/mysql
> sudo mount /var/log/mysql
> sudo mount /var/log/iexperiment
> sudo mount /var/local/iexperiment
</pre>
<p>If MySQL has already been installed and setup, then instead of making the /mysql directories, we would move (mv) the existing MySQL directories to the EBS volume.  We continue from the snippet above remaking mysql directories that are used as mount bind points. </p>
<pre>> sudo mkdir /ebs1/etc
> sudo mkdir /ebs1/lib
> sudo mkdir /ebs1/log
> sudo mv /etc/mysql     /vol/etc/
> sudo mv /var/lib/mysql /vol/lib/
> sudo mv /var/log/mysql /vol/log/

> sudo mkdir /etc/mysql
...
</pre>
</div>
<div class="codeBox">
<h3 id="installing-MySQL">Installing MySQL</h3>
<p>MySQL and MySQL Server (mysqld) are available from the Amazon Yum repository.  Like update snippets above, the snippet below has been edited to show only what is necessary.</p>
<pre>> sudo yum install mysql
Is this ok [y/N]: y

> sudo yum install mysql-server
Is this ok [y/N]: y
</pre>
<p>After installing MySQL and MySQL Server, we start the MySQL service. </p>
<pre>
> sudo service mysqld start
Initializing MySQL database:  Installing MySQL system tables...
OK
Filling help tables...
OK

To start mysqld at boot time you have to copy
support-files/mysql.server to the right place for your system

PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:

/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h ip-10-176-31-62 password 'new-password'

Alternatively you can run:
/usr/bin/mysql_secure_installation

which will also give you the option of removing the test
databases and anonymous user created by default.  This is
strongly recommended for production servers.

See the manual for more instructions.

You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &#038;

You can test the MySQL daemon with mysql-test-run.pl
cd /usr/mysql-test ; perl mysql-test-run.pl

Please report any problems with the /usr/bin/mysqlbug script!

[  OK  ]
Starting mysqld:                                           [  OK  ]
</pre>
<p>Finally the mysql_secure_installation script is run.</p>
<pre>
> /usr/bin/mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] Y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!

By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
... Success!

By default, MySQL comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!
    </pre>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="database-setup">Set Up the iExperiment Database</h3>
<ol>
<li>Log in as root to the MySQl database.  We recommend that you not put the root password in the mysql command, so that it does not end up in .bash_history.</li>
<li>Create a user &lsquo;iexperiment&lsquo;@&lsquo;localhost&lsquo;. </li>
<li>Grant the iexperiment user appropriate privileges.</li>
</ol>
<pre>> mysql -h localhost -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.1.52 Source distribution

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create user 'iexperiment'@'localhost' identified by 'iexperimentpassword';
Query OK, 0 rows affected (0.00 sec)

mysql> grant usage on *.* to 'iexperiment'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on *.* to 'iexperiment'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye
    </pre>
<ol start="4">
<li>Create the /var/log/iexperiment, /var/local/iexperiment and /var/local/iexperiment/ddl directories.</li>
<li>Upload the iExperiment SQL files to the /var/local/iexperiment/ddl directory using an FTP application that supports SSL, such at <a target="_blank" href="http://filezilla-project.org/">FileZilla</a>. </li>
</ol>
<pre>> sudo mkdir /var/log/iexperiment
> sudo mkdir /var/local/iexperiment
> sudo mkdir /var/local/iexperiment/ddl
    </pre>
<ol start="6">
<li>Log in to MySQL as iexperiment.</li>
<li>Create a database named iexperiment. </li>
<li>Load the database by sourcing the initial_setup.sql file. </li>
</ol>
<pre>
> pushd /var/local/iexperiment/ddl
/var/local/iexperiment/ddl ~
> ls -lt
total 136
-rw-rw-r-- 1 root root   917 Jul 17 21:22 initial_setup.sql
-rw-rw-r-- 1 root root  3465 Jul 17 21:08 insert_permissions_START-UP.sql
-rw-rw-r-- 1 root root   944 Jul 17 21:08 insert_admin_START-UP.sql
-rw-rw-r-- 1 root root 22612 Jul 14 17:33 create_tables.sql
-rw-rw-r-- 1 root root 73893 Jul 14 17:09 insert_record_categories.sql
-rw-rw-r-- 1 root root 18355 Jul 14 17:09 create_constraints.sql
-rw-rw-r-- 1 root root   932 Jul 14 17:08 insert_admin.sql

> mysql -h localhost -u iexperiment -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.1.52 Source distribution

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show grants;
+-----------------------------------------------------------------------------------------------------------------------------+
| Grants for iexperiment@localhost                                                                                            |
+-----------------------------------------------------------------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'iexperiment'@'localhost' IDENTIFIED BY PASSWORD '*BAA33824FACE624B5B0AAC8A604733A5648A7A6B' |
+-----------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> create database iexperiment;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| iexperiment        |
| mysql              |
+--------------------+
3 rows in set (0.00 sec)

mysql> use iexperiment;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> source initial_setup.sql;

Query OK, 1 row affected (0.00 sec)
.
.
.
Query OK, 1 row affected (0.00 sec)

mysql> show tables;
+------------------------+
| Tables_in_iexperiment  |
+------------------------+
| admin_group_member     |
| ...
| version                |
+------------------------+
55 rows in set (0.00 sec)

mysql> select * from version;
+-------------+----------------------------------+
| version_num | comment                          |
+-------------+----------------------------------+
|           6 | May 25, 2010 - Switch to Records |
+-------------+----------------------------------+
1 row in set (0.00 sec)

mysql> exit
Bye
  </pre>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="SSL-certificate">Create SSL Certificate</h3>
<p>iExperiment runs under the secure HTTPS protocol; thus, we need a Secure Sockets Layer (SSL) certificate.  If you already have a wildcard certificate for your domain, then you can skip this step. </p>
<p>Note, that if you use a self-signing certificate, then your iExperiment users will be notified of this.  In FireFox they will see a &#8220;This Connection is Untrusted&#8221; page, in which they will need to open the &#8220;I understand the Risks&#8221; link and click on the &#8220;Add Exception&#8230;&#8221; button. </p>
<ol>
<li>Make a directory for the SSL certificate.</li>
<li>Generate the self-signing SSL certificate.  In the snippet below, the certificate&#8217;s file name, temp.iexperiment.bin, reflects the URL we are using.</li>
</ol>
<pre>
> sudo mkdir /usr/etc/cert
> cd /usr/etc/cert

> sudo keytool -genkey -alias tomcat -keypass sslcert1 -keystore temp.iexperiment.bin -storepass sslcert1
What is your first and last name?
[Unknown]:  Marc Whitlow
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:  Colabrativ, Inc.
What is the name of your City or Locality?
[Unknown]:  El Sobrante
What is the name of your State or Province?
[Unknown]:  California
What is the two-letter country code for this unit?
[Unknown]:  US
Is CN=Marc Whitlow, OU=Unknown, O="Colabrativ, Inc.", L=El Sobrante, ST=California, C=US correct?
[no]:  y

> ls -l
total 4
-rw-r--r-- 1 root root 1292 Jul 18 02:30 temp.iexperiment.bin
    </pre>
<p>Write down the certificate &#8220;keypass&#8221; as you will need it to set up Tomcat.</p>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="apache-tomcat">Setup Apache &amp; Tomcat</h3>
<ol>
<li>Install <a target="_blank" href="http://httpd.apache.org/docs/2.0/programs/httpd.html">Apache Hypertext Transfer Protocol Server</a> (httpd), <a target="_blank" href="http://tomcat.apache.org/tomcat-6.0-doc/index.html">Apache Tomcat 6</a> (tomcat6), Tomcat&#8217;s web application service (tomcat6-webapps) and <a target="_blank" href="http://www.modssl.org/">Apache Interface to OpenSSL</a> (mod_ssl) from Amazon&#8217;s Yum repository.</li>
<li>Start the Apache (httpd) and Tomcat (tomcat6) services. </li>
</ol>
<pre>> sudo yum install httpd
Is this ok [y/N]: y

> sudo yum install tomcat6
Is this ok [y/N]: y

> sudo yum install tomcat6-webapps
Is this ok [y/N]: y

> sudo yum install mod_ssl
Is this ok [y/N]: y

> sudo service httpd start
Starting httpd:                                            [  OK  ]
> sudo service tomcat6 start
Starting tomcat6:                                          [  OK  ]
    </pre>
<p>Now we can check to see if the “Amazon Linux AMI Test Page” loads in a Browser using:</p>
<ul>
<li>EC2 Instance&#8217;s public URL that is found in the EC2 Instance information on the AWS Management Console, e.g. http://ec2-204-236-137-138.us-west-1.compute.amazonaws.com</li>
<li>The URL that was assigned to the Elastic IP address associated with the EC2 Instance in the Domain Name Server (DNS), e.g. http://temp.iexperiment.net/</li>
</ul>
<p>Next, we will configure Tomcat to support applications and services under the secure https protocol on port 8443.  We do this by editing the server.xml file in /etc/tomcat.</p>
<pre>
> cd /etc/tomcat6
> sudo cp -p server.xml server.xml.orig
> sudo vi server.xml
> diff server.xml.orig server.xml
83,88c83,92
<     <!--
<     <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
<                maxThreads="150" scheme="https" secure="true"
<                clientAuth="false" sslProtocol="TLS" />
<     -->
<
---
>
>     <Connector port="8443"
>                protocol="HTTP/1.1"
>                SSLEnabled="true"
>                maxThreads="150"
>                scheme="https" secure="true"
>                clientAuth="false" sslProtocol="TLS"
>                keystoreFile="/usr/etc/cert/temp.iexperiment.bin"
>                keystorePass="sslcert1" />

> sudo service tomcat6 restart
Stopping tomcat6:                                          [  OK  ]
Starting tomcat6:                                          [  OK  ]
    </pre>
<p>We should now beable to see the sample web applications supplied with the tomcat6-webapps Yum distribution found in /var/lib/tomcat6/webapps/sample, using the following URLs: </p>
<ul>
<li>&#8220;EC2 Public URL&#8221;:8080/sample e.g. http://ec2-204-236-137-138.us-west-1.compute.amazonaws.com:8080/sample </li>
<li>http://&#8221;iExperiment Domain&#8221;:8080/sample, e.g. http://temp.iexperiment.net:8080/sample</li>
<li>https://&#8221;iExperiment Domain&#8221;:8443/sample, e.g. https://temp.iexperiment.net:8443/sample</li>
</ul>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="index-html">Adding index.html</h3>
<p>Upload the iExperiment index.html page and any images associated with the page to the /var/www/html directory.  You can either overwrite the existing index.html page or rename it.
</p></div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="iExperiment-applications">iExperiment Applications Installation</h3>
<p>iExperiment has three applications: Admin, Record and ResetPassword.</p>
<ol>
<li>Upload the iExperiment applications .war files (admin.war, record.war and resetPassword.war) to the /var/lib/tomcat6/webapps/ directory in the EC2 server. </li>
<li>Stop the Tomcat service.</li>
<li>Create directories for the attachments and the Lucene search engine index.</li>
<li>For each of the iExperiment applications.
<ol>
<li>Create a directory for the application in /var/lib/tomcat6/webapps/ </li>
<li>Change the group to tomcat.</li>
<p>            li>Unzip the contents of the war file into the newly created directory.</li>
<li>Upload and replace the &#8220;application&#8221;.html file with deployment specific version. </li>
<li>Add deployment specific images to the images directory.</li>
<li>Upload and replace existing iexperiment.properties, dbpool.properties and log4j.properties with files specific for this deployment.</li>
</ol>
</li>
<li>Start the Tomcat service.</li>
</ol>
<pre>> sudo service tomcat6 stop
Stopping tomcat6:                                          [  OK  ]

> sudo mkdir /var/local/iexperiment/attachments
> sudo mkdir /var/local/iexperiment/lucene
> sudo chown -R tomcat:tomcat /var/local/iexperiment/*

> cd /var/lib/tomcat6/webapps/
> ls -lt
total 12
drwxrwxr-x 5 root tomcat 4096 Jul 14 14:53 sample
drwxrwxr-x 5 root tomcat 4096 Jul 14 14:53 examples
drwxrwxr-x 3 root tomcat 4096 Jul 14 14:53 ROOT

> sudo mkdir record
> sudo mkdir admin
> sudo mkdir resetPassword
> sudo chgrp tomcat *

# Begein of admin application configuration.
> pushd admin
> sudo unzip ../admin.war

# After uploading Admin.html
> sudo chown -R root:root *.html

# After uploading deployment specific images to the images diectory.
> pushd images
> sudo chown -R root:root *
> popd

# After uploading the deployment specific properties files
# to the WEB-INF/classes directory
> pushd WEB-INF/classes/
> sudo chown -R root:root *.properties
> ls -lt
total 28
-rw-rw-r-- 1 root root 1287 Jul 14 18:33 log4j.properties
-rw-rw-r-- 1 root root 2020 Jul 14 18:33 iexperiment.properties
-rw-rw-r-- 1 root root 1514 Jul 14 18:33 dbpool.properties
drwxr-xr-x 3 root root 4096 Jul 14 17:49 net
drwxr-xr-x 3 root root 4096 Jul 14 17:49 org
drwxr-xr-x 4 root root 4096 Jul 14 17:49 com
-rw-r--r-- 1 root root 1370 May  3 19:05 mail.properties

# End of admin application configuration.
# Repeat for the record and resetPassword applications. 

> sudo service tomcat6 start
Starting tomcat6:                                          [  OK  ]
    </pre>
</div>
<p><!-- codeBox  --></p>
<div class="codeBox">
<h3 id="removing-8443">Removing Port 8443 from HTTPS Requests</h3>
<p>The final task in setting up the iExperiment Server is to remove the port number from the secure https requests.  We do this by relay the port 443 TCP connections to port 8443 using iptables in the <a target="_blank" href="http://www.netfilter.org/">Netfilter package</a> that already installed on the EC2 instance. </p>
<ol>
<li>Using iptables redirect the incoming port 443 request to port 8443.</li>
<li>Using iptables redirect the output from the incoming port 443 request to port 8443.</li>
<li>We can see these rules in the &#8220;nat&#8221; table using the command &#8220;sudo iptables -t nat -L&#8221;.</li>
<li>Save the iptable in /etc/iptables.conf, and change ownership to root.</li>
<li>Finally, add &#8220;/sbin/iptables-restore &lt; /etc/iptables.conf&#8221; to the bottom to /etc/rc.local file.</li>
</ol>
<pre>> sudo iptables -t nat -I PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8443
> sudo iptables -t nat -I OUTPUT -p tcp --dport 443 -j REDIRECT --to-ports 8443

> sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  anywhere             anywhere            tcp dpt:https redir ports 8443

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  anywhere             anywhere            tcp dpt:https redir ports 8443

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

> sudo iptables-save > iptables.conf
> more iptables.conf
# Generated by iptables-save v1.4.7 on Thu Sep  8 03:32:23 2011
*nat
&#58;PREROUTING ACCEPT [5:300]
:OUTPUT ACCEPT [50:3801]
&#58;POSTROUTING ACCEPT [50:3801]
-A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
-A OUTPUT -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
COMMIT
# Completed on Thu Sep  8 03:32:23 2011

> sudo cp -p iptables.conf /etc/.
> sudo chown -R root:root /etc/iptables.conf
> sudo ls -l /etc/iptables.conf
-rw-rw-r-- 1 root root 332 Sep  8 03:32 /etc/iptables.conf

> sudo vi /etc/rc.local
> more /etc/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local
/sbin/iptables-restore &lt; /etc/iptables.conf
    </pre>
</div>
<p><!-- codeBox  --></p>
<h3>Closing Remarks</h3>
<p>iExperiment run on a typical AWS Apache Tomcat deployment. </p>
<h3>Resources</h3>
<ol>
<li>&ldquo;Configuring MySQL to use the EBS volume&rdquo; section of Eric Hammond&#8217;s article on <a target="_blank" href="http://aws.amazon.com/articles/1663?_encoding=UTF8&amp;jiveRedirect=1">Running MySQL on Amazon EC2 with EBS (Elastic Block Store)</a>.</li>
<li><a target="_blank" href="http://www.puschitz.com/InstallingTomcat.html">Installing Apache Tomcat on Linux</a> by Werner Puschitz.</li>
<li><a target="_blank" href="http://www.cyberciti.biz/faq/how-do-i-save-iptables-rules-or-settings/">How Do I Save Iptables Rules or Settings?</a> by Vivek Gite. </li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/setup-of-iexperiment-on-amazons-elastic-compute-cloud-ec2-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setup of Amazon&#8217;s Elastic Compute Cloud (EC2) Server for iExperiment</title>
		<link>http://www.colabrativ.com/setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment/</link>
		<comments>http://www.colabrativ.com/setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment/#comments</comments>
		<pubDate>Mon, 29 Aug 2011 17:37:23 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Elastic Compute Cloud]]></category>
		<category><![CDATA[electronic notebook]]></category>
		<category><![CDATA[ELN]]></category>
		<category><![CDATA[iExperiment]]></category>
		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=226</guid>
		<description><![CDATA[A research organization&#8217;s experiment records are the foundation of its intellectual property, and, as such, must be stored in a way that allows the research organization to maintain control over these records. Enterprise electronic notebooks, such as our iExperiment, store &#8230; <a href="http://www.colabrativ.com/setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A research organization&#8217;s experiment records are the foundation of its intellectual property, and, as such, must be stored in a way that allows the research organization to maintain control over these records.  Enterprise electronic notebooks, such as our iExperiment, store their experiment records on a server.  Many organizations, including Colabrativ, Inc., are using cloud computing to lower the cost of a server and IT costs in general.  Amazon&#8217;s <a target="_blank" href="http://aws.amazon.com/ec2/">Elastic Compute Cloud (EC2)</a> is one of the lower cost cloud service providers.  Amazon is <a target="_blank" href="http://sas70.com/sas70_overview.html">Statement on Auditing Standards No. 7 (SAS70)</a> compliant.  <a target="_blank" href="http://aws.amazon.com/about-aws/whats-new/2009/11/11/aws-completes-sas70-type-ii-audit/">They completed the Type II audit in 2009</a>, so you know they are doing everything they can to keep our data secure.  Amazon Web Services places the responsibility of the enterprise application setup and maintenance on the client&#8217;s administrator.  Other full-service SAS70-complaint cloud service providers will happily take on these responsibilities for you, for a fee. </p>
<p>In this post and in the following post, I will show you how we setup our enterprise electronic notebook application, iExperiment, on an Amazon EC2 server.  This first post covers the launch of the Amazon EC2 server and attachment of <a target="_blank" href="http://aws.amazon.com/ebs/">Elastic Block Storage</a> volume to the server.  The cloud equivalent of purchasing a server and disk, plugging it in, and connecting it to the network.  Experienced Amazon EC2 administrators may want to take a quick look at <a href="#requirements">iExperiment Server Requirements</a> and then move on to the second post on the setup and configuring of an EC2 server for iExperiment. </p>
<ul>
<li><a href="#requirements">iExperiment Server Requirements</a></li>
<li><a href="#ec2-instance-setup">Setup of Amazon Web Services EC2 Instance</a></li>
<li><a href="#attaching-ebs">Creating and Attaching an Elastic Block Storage Volume (optional)</a></li>
<li><a href="#dns-server">Assigning URL of the iExperiment EC2 Server on the DNS Server</a></li>
</ul>
<p>In the second post we will go over the setup and configuration of the EC2 server and the installation and setup of iExperiment on it.  Topic in the post include: </p>
<ul>
<li>Updating the Server</li>
<li>Installing MySQL</li>
<li>iExperiment Database Setup</li>
<li>Mounting Elastic Block Storage Volume (optional)</li>
<li>SSL Certificate Creation</li>
<li>Setup Apache &amp; Tomcat</li>
<li>Adding index.html</li>
<li>iExperiment Applications Installation</li>
</ul>
<h3 id="requirements">iExperiment Server Requirements</h3>
<p>The requirements of our enterprise electronic notebook application, iExperiment, are: </p>
<ol>
<li>Linux hosting web environment:  We normally use Apache and Tomcat.</li>
<li>MySQL database.</li>
<li>Mail server:  By default iExperiment uses the iExperiment.net mail server.</li>
</ol>
<p>In addition to these requirements, we recommend that you have the following before setting up iExperiment.</p>
<ol>
<li>A subdomain name under your domain name for iExperiment, for example iexperiment.example.org. </li>
<li>An administrator mail address on your mail server, e.g. admin@example.org.</li>
</ol>
<h3 id="ec2-instance-setup">Setup of Amazon Web Services EC2 Instance</h3>
<p>If you are not familiar with Amazon Web Services, we recommend that you read the <a target="_blank" href="http://docs.amazonwebservices.com/AWSEC2/latest/GettingStartedGuide/">Amazon Elastic Compute Cloud Getting Started Guide</a>.  There you can find instructions on how to sign up for Amazon EC2, which tell you to &#8220;Go to <a target="_blank" href="http://aws.amazon.com/ec2">http://aws.amazon.com/ec2</a>, click on the <strong>Sign Up for Amazon EC2</strong>, and follow the on-screen instructions.&#8221; </p>
<p>After signing on in the <a target="_blank" href="http://aws.amazon.com/console/">Amazon Management Console</a>, and selecting a region, the following tasks are performed. </p>
<ol>
<li>
<h4>Select an Amazon Region for the iExperiment Server</h4>
<p>Select a <strong>Region</strong> from the region pull-down menu at the top of the Navigation panel.  We are in Northern California, so we normally select the <span style="color:#004B91">US West (N. California)</span> region.
  </li>
<li>
<h4>Create Security Group</h4>
<p>Open the <strong>Security Groups</strong> panel by clicking on its link under <span style="color:gray">NETWORK &amp; SECURITY</span> in the Navigation panel. </p>
<ol>
<li>Click on the &#8220;Create Security Group&#8221; button at the top of the Security Group panel.<br />
         This will bring up the &#8220;Create Security Group&#8221; popup.
       </li>
<li>In the &#8220;Create Security Group&#8221; popup, fill in the following information:<br />
<table>
<tr>
<td>Name:</td>
<td>iExperiment</td>
</tr>
<tr>
<td>Description:</td>
<td>iExperiment open ports: 22 (SSH), 80 and 8080 (HTTP), and 443 and 8443 (HTTPS)</td>
</tr>
<tr>
<td>VPC:</td>
<td>No VPC</td>
</tr>
</table>
<p>         Then click on the &#8220;<span style="color:#004B91">Yes, Create</span>&#8221; button.
        </li>
<li>Click on the iExperiment security group, and click on the &#8220;Inbound&#8221; tab.</li>
<li>In the &#8220;Inbound&#8221; tab add the following rules:
<ol>
<li>From the &#8220;Create a new rule&#8221; pull-down menu, select &#8220;SSH&#8221;,<br />
                then click on the &#8220;Add Rule&#8221; button.</li>
<li>From the &#8220;Create a new rule&#8221; pull-down menu, select &#8220;HTTP&#8221;,<br />
                then click on the &#8220;Add Rule&#8221; button.</li>
<li>From the &#8220;Create a new rule&#8221; pull-down menu, select &#8220;HTTPS&#8221;,<br />
                then click on the &#8220;Add Rule&#8221; button.</li>
<li>From the &#8220;Create a new rule&#8221; pull-down menu, select &#8220;Custom TCP rule&#8221;,<br />
                enter the &#8220;port range&#8221; of 8080,<br />
                then click on the &#8220;Add Rule&#8221; button.</li>
<li>From the &#8220;Create a new rule&#8221; pull-down menu, select &#8220;Custom TCP rule&#8221;,<br />
                enter the &#8220;port range&#8221; of 8443,<br />
                then click on the &#8220;Add Rule&#8221; button.<br />
                <br/>The resulting security table contains the following rules: <br/><br />
                <img src="http://www.colabrativ.com/images/iExperiment_EC2_security_group.png" alt="The enterprise iExperiment electronic notebook Amazon EC2 security group." />
            </li>
<li>After adding all of the Rules, click on the &#8220;Apply Rule Changes&#8221; button at the bottom of the Inbound* tab.</li>
</ol>
</li>
</ol>
<p>&nbsp;</p>
</li>
<li>
<h4>Create Key Pair</h4>
<p>Open the <strong>Key Pairs</strong> panel by click on its link under <span style="color:gray">NETWORK &amp; SECURITY</span> in the Navigation panel. </p>
<ol>
<li>Click on the &#8220;Create Key Pair&#8221; button at the top of the Key Pairs panel.<br />
          This will bring up the &#8220;Create Key Pair&#8221; popup.
      </li>
<li>Supply a &#8220;Key Pair Name&#8221;, then click on the &#8220;<span style="color:#004B91">Create</span>&#8221; button.<br />
          Amazon will create the key pair and download the file to you.<br />
          Save the .pem file somewhere accessible to you.
      </li>
</ol>
<p>&nbsp;</p>
</li>
<li>
<h4>Launch EC2 Instance</h4>
<p>Open the <strong>Instances</strong> panel by clicking on its link under <span style="color:gray">INSTANCES</span> in the Navigation panel. </p>
<ol>
<li>Click on the &#8220;Launch Instance&#8221; button at the top of the My Instances panel.<br />
           This will bring up the &#8220;Request Instances Wizard&#8221; popup. </li>
<li>Click the &#8220;Select&#8221; button to the right of the &#8220;Basic 32-bit Amazon Linux AMI 2011.02.1 Beta&#8221; under the &#8220;Quick Start&#8221; tab in the Request Instances Wizard.</li>
<li>Fill in the Instance Details:<br />
<table>
<caption>Instance Details</caption>
<tr>
<td>Number of Instances:</td>
<td>1</td>
</tr>
<tr>
<td>Availability Zone:</td>
<td>us-west-1a</td>
</tr>
<tr>
<td>Instance Type:</td>
<td>Small (m1.small, 1.7 GB)</td>
</tr>
</table>
<p>           Then click on the &#8220;<span style="color:#004B91">Continue</span>&#8221; button at the bottom of the popup.
       </li>
<li>We normally change nothing in the &#8220;<span style="color:#004B91">Advanced Instance Options</span>&#8220;.<br />
           Click on the &#8220;<span style="color:#004B91">Continue</span>&#8221; button at the bottom of the popup. </li>
<li>If you have multiple EC2 instances, you may want to add Tags to the iExperiment instance.<br />
           Click on the &#8220;<span style="color:#004B91">Continue</span>&#8221; button at the bottom of the popup. </li>
<li>Choose the &#8220;Choose from your existing Key Pairs&#8221; option, then select the key pair for iExperiment from a &#8220;Your existing Key Pair&#8221; pull-down menu.<br />
           Click on the &#8220;<span style="color:#004B91">Continue</span>&#8221; button at the bottom of the popup. </li>
<li>Choose the iExperiment security group using the &#8220;Choose one or more of your existing Security Groups&#8221; option from list of security groups, then<br />
           click on the &#8220;<span style="color:#004B91">Continue</span>&#8221; button at the bottom of the popup. </li>
<li>Review the configuration of your EC2 Instance request, then<br />
           click on the &#8220;<span style="color:#004B91">Launch</span>&#8221; button at the bottom of the &#8220;Request Instances Wizard&#8221; popup.<br />
           <img width="580px" src="http://www.colabrativ.com/images/Amazon_EC2_Instance_Review.png" alt="Review section Amazon EC2 Request Instances Wizard popup for a server capable of running Colabrativ's enterprise electronic notebook, iExpertiment." />
        </li>
</ol>
<p>It&#8217;s worth noting the id, Availability Zone, and Public DNS of the EC2 instance you created by clicking on the instance in the &#8220;My Instances&#8221; panel.
  </li>
<li>
<h4>Create an Elastic IP</h4>
<p>Amazon&#8217;s <a target="_blank" href="http://aws.amazon.com/articles/1346">Elastic IP Addresses</a> are static IP addresses that you can associate with an Amazon EC2 server.  Open the Addresses panel by clicking on the <strong>Elastic IPs</strong> link under <span style="color:gray">NETWORK &amp; SECURITY</span> in the Navigation panel. </p>
<ol>
<li>Click on the &#8220;Allocate New Address&#8221; button at the top of the &#8220;Addresses&#8221; panel.<br />
          This will bring up the &#8220;Allocate New Address&#8221; popup.<br />
          Click on the &#8220;<span style="color:#004B91">Yes, Allocate</span>&#8221; button in the popup.<br />
          This will create a new address.
      </li>
<li>Click on the new Elastic IP address and select Associate Address.<br />
          This will bring up the &#8220;Associate Address&#8221; popup.<br />
          Select the iExperiment EC2 Instance from the &#8220;Instance&#8221; pull-down list and<br />
          click on the &#8220;<span style="color:#004B91">Yes, Associate</span>&#8221; button in the popup.
      </li>
</ol>
<p>The eleastic IP address will be needed when setting up the Domain Name Server, below, so make a note of it.
  </li>
</ol>
<h3 id="attaching-ebs">Creating and Attaching an Elastic Block Storage Volume (optional)</h3>
<p>We highly recommend that you place your experiment records created in iExperiment on an EC2 server in an <a target="_blank" href="http://aws.amazon.com/ebs/">Elastic Block Storage (EBS)</a> volume.  EBS isolates your data from the server failures and its scalable.  An existing volume can be copied to a large volume as your iExperiment records increase.  From the Amazon Management Console open the EBS Volumes panel by clicking on the <strong>Volumes</strong> link under <span style="color:gray">ELASTIC BLOCK STORE</span> in the Navigation panel. </p>
<ol>
<li>Click on the &#8220;Create Volume&#8221; button at the top of the &#8220;EBS Volumes&#8221; panel.<br />
      This will bring up the &#8220;Create Volume&#8221; popup.
  </li>
<li>In the &#8220;Create Volume&#8221; popup enter a volume <strong>Size</strong>, and <strong>Availability Zone</strong>.<br />
      The volume <strong>Size</strong> you choose will primarily depend on the size of the figures and attachment the researchers using iExperiment plan to associate with their experiment records.  10 GiB is a good starting size.  The <strong>Availability Zone</strong> must be the same as the iExperiment instance.<br />
      Click on &#8220;<span style="color:#004B91">Yes, Create</span>&#8221; button in the popup.
  </li>
<li>Click on the EBS volume you just created and select &#8220;Attach Volume&#8221;.<br />
      This will bring up the &#8220;Attach Volume&#8221; popup with <strong>Volume</strong> already filled in.<br />
      Select the iExperiment EC2 instance, shown by id, from the <strong>Instances</strong> pull-down menu.<br />
      Click on the &#8220;<span style="color:#004B91">Yes, Attach</span>&#8221; button in the popup to attach the EBS volume to the iExperiment instance.
  </li>
</ol>
<h3 id="dns-server">Assigning URL of the iExperiment EC2 Server on the DNS Server</h3>
<p>Here we will use the domain name temp.iExperiment.net, but you will be using a sub-domain of your domain such as iexperiment.example.com.  We are using Kattare Internet Services for our DNS server.  There we associate the AWS Elastic IP address with both the sub-domain and its secure variant in the iExperiment Zone File:</p>
<table>
<tr>
<td>temp</td>
<td>IN</td>
<td>A</td>
<td>50.18.109.21</td>
</tr>
<tr>
<td>www.temp</td>
<td>IN</td>
<td>A</td>
<td>50.18.109.21</td>
</tr>
<tr>
<td>securetemp</td>
<td>IN</td>
<td>A</td>
<td>50.18.109.21</td>
</tr>
<tr>
<td>www.securetemp</td>
<td>IN</td>
<td>A</td>
<td>50.18.109.21</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/setup-of-amazons-elastic-compute-cloud-ec2-server-for-iexperiment/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Calendar and Timestamp Duration Determination Method in Java</title>
		<link>http://www.colabrativ.com/calendar-and-timestamp-duration-determination-method-in-java/</link>
		<comments>http://www.colabrativ.com/calendar-and-timestamp-duration-determination-method-in-java/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 17:02:58 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[duration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[timestamp]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=212</guid>
		<description><![CDATA[If you are interested in determining the duration between two dates in Java, you will find few, if any, examples of how one goes about performing this task. There are a number of Java duration classes, such as the Android &#8230; <a href="http://www.colabrativ.com/calendar-and-timestamp-duration-determination-method-in-java/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you are interested in determining the duration between two dates in Java, you will find few, if any, examples of how one goes about performing this task.  There are a number of Java duration classes, such as the <a target="_blank" href="http://hi-android.info/src/com/android/providers/calendar/Duration.java.html">Android Duration</a> class that allow you to define a duration and add it to a <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html">Calendar</a> instance, but how to determine a duration is harder to find. </p>
<p>The task itself is relatively easy to accomplish by using the two dates as <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html">Calendar</a> instances.  The <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#YEAR">YEAR</a>, <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#DAY_OF_YEAR">DAY_OF_YEAR</a>, <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#HOUR_OF_DAY">HOUR_OF_DAY</a>, and <a target="_blank" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#MINUTE">MINUTE</a> fields can be used to obtain the corresponding values for each of the Calender instances, which can then be subtracted from one another.  Next we correct for the negative values and leap years.  Finally, we format the results as a string.</p>
<p>I have implemented this as a static method <strong>duration</strong> in the Java class CalendarUtilites, shown below.  I have also provided a <a target="_blank" href="http://junit.sourceforge.net/javadoc/">JUnit</a> test class, CalendarUtilitiesTests, at the bottom of the page.</p>
<div class="codeBox">
<h3>CalendarUtilities: Calendar Utilities with Duration Determination Method</h3>
<pre>package com.colabrativ.common.server.utility;

import java.sql.Timestamp;
import java.util.Calendar;

/**
 * Calendar Utility Class
 *
 * @author Marc Whitlow
 *         Colabrativ, Inc.
 *         http://www.colabrativ.com
 */
 public class CalendarUtilities {

    /**
     * Determine the duration between the start and end dates.
     *
     * @param startDate Duration starting date
     * @param endDate Duration end date
     *
     * @return String describing the time between the start and end dates,
     * e.g. 2 years 47 days 6 hours and 1 minute.
     */
    public static String duration(Timestamp startDate, Timestamp endDate) {

        Calendar startCalendar = Calendar.getInstance();
        Calendar endCalendar   = Calendar.getInstance();
        startCalendar.setTime( startDate);
        endCalendar  .setTime( endDate);

        return duration(startCalendar, endCalendar);
    }

    /**
     * Determine the duration between the start and end dates.
     *
     * @param startCalendar Duration starting date
     * @param endCalendar Duration end date
     *
     * @return String describing the time between the start and end dates,
     * e.g. 2 years 1 day 6 hours and 23 minutes.
     */
    public static String duration(Calendar startCalendar, Calendar endCalendar)
    {
        int years 	= endCalendar.get(Calendar.YEAR) 		- startCalendar.get(Calendar.YEAR);
        int days 	= endCalendar.get(Calendar.DAY_OF_YEAR) - startCalendar.get(Calendar.DAY_OF_YEAR);
        int hours 	= endCalendar.get(Calendar.HOUR_OF_DAY) - startCalendar.get(Calendar.HOUR_OF_DAY);
        int mins 	= endCalendar.get(Calendar.MINUTE) 		- startCalendar.get(Calendar.MINUTE);

        if (mins < 0) {
            hours = hours - 1;
            mins  = mins + 60;
        }

        if (hours < 0) {
            days  = days - 1;
            hours = hours + 24;
        }

        // Leap year corrections
        int daysInYear = 365;
        Calendar leapYear = Calendar.getInstance();
        leapYear.set( startCalendar.get(Calendar.YEAR), 11, 31, 23, 59, 59);
        if (leapYear.get(Calendar.DAY_OF_YEAR) == 366) {
            leapYear.set( startCalendar.get(Calendar.YEAR), 1, 29, 23, 59, 59);
            if (startCalendar.before(leapYear))
                daysInYear = 366;
        }

        leapYear.set( endCalendar.get(Calendar.YEAR), 11, 31, 23, 59, 59);
        if (leapYear.get(Calendar.DAY_OF_YEAR) == 366) {
            leapYear.set( endCalendar.get(Calendar.YEAR), 1, 29, 23, 59, 59);
            if (endCalendar.after(leapYear)) {
                daysInYear = 366;
                if (years > 0)
                    days = days - 1;
            }
        }

        if (days < 0) {
            years--;
            days = days + daysInYear;
        }

        StringBuilder durationSB = new StringBuilder();
        if (years > 0) {
            durationSB.append( years);
            addUnits( durationSB, years, "year");
        }

        if (days > 0) {
            durationSB.append( days);
            addUnits( durationSB, days, "day");
        }

        if (hours > 0) {
            durationSB.append( hours);
            addUnits( durationSB, hours, "hour");
        }

        if (mins > 0) {
            durationSB.append( mins);
            addUnits( durationSB, mins, "minute");
        }

        return durationSB.toString();
    }

    private static void addUnits( StringBuilder stringBuilder, int value, String units) {

        stringBuilder.append( " ");
        if (value == 1)
            stringBuilder.append( units + " ");
        else
            stringBuilder.append( units + "s ");
    }
}
</pre>
</div>
<p>This static class does not create a duration object.  It simply returns a string that describes the duration.  It would be fairly straightforward to wrap the duration method in a Duration class, similar to <a target="_blank" href="http://hi-android.info/src/com/android/providers/calendar/Duration.java.html">Android Duration</a>. </p>
<p>The other thing this class does not do is to output the number of weeks.  I chose to output the number of days instead of the number of weeks and days, because in practice most people speak of 60 and 90 day events and not 8 weeks and 4 days, or 12 weeks and 6 days.  It is relatively easy to convert from days to weeks and days.  You simply divide the number of days by 7 to get weeks and subtract seven times the number of weeks from days.  Then, you need to add the weeks information to the StringBuilder durationSB.  This code addition, shown in the snippet below, is placed after the years information has been written to the StringBuilder, and before the days information is written to the StringBuilder. </p>
<div class="codeBox">
<h3>Days to Weeks and Days Code Snippet</h3>
<pre>
        int weeks = days / 7;
        days = days - (7 * weeks);

        if (days > 0) {
        durationSB.append( weeks);
        addUnits( durationSB, weeks, "week");
        }
</pre>
</div>
<p>To complete the addition of weeks, the assertEquals statements in the CalendarUtilitiesTests class, shown below, would need to be updated. </p>
<div class="codeBox">
<h3>CalendarUtilitiesTests:  JUnit Testing of the Calendar Duration Utility</h3>
<pre>
package com.colabrativ.common.server.utility;

import java.sql.Timestamp;
import java.util.Calendar;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Unit testing of the CalendarUtilities class.
 *
 * @author Marc Whitlow
 *         Colabrativ, Inc.
 *         http://www.colabrativ.com
 */
public class CalendarUtilitiesTests {

    @Before
    public void setUp() {}

    @Test
    public void timestampDurationTests()
    {
        // A minute difference
        Calendar calendar = Calendar.getInstance();
        calendar.set( 2011, 6, 22, 9, 34, 18);   // 2011-07-22 09:34:18
        Timestamp startDate = new Timestamp( calendar.getTimeInMillis());
        calendar.set( 2011, 6, 22, 9, 35, 18);   // 2011-07-22 09:35:18
        Timestamp endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "1 minute ", CalendarUtilities.duration( startDate, endDate));

        // An hour and 45 minutes
        calendar.set( 2011, 6, 22, 11, 19, 59);  // 2011-07-22 11:19:59
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "1 hour 45 minutes ", CalendarUtilities.duration( startDate, endDate));

        // A day 8 hours and 30 minutes
        calendar.set( 2011, 6, 23, 18, 04, 59);  // 2011-07-23 18:04:59
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "1 day 8 hours 30 minutes ", CalendarUtilities.duration( startDate, endDate));

        // 60 days 18 hours and 30 minutes
        calendar.set( 2011, 8, 21, 4, 04, 0);   // 2011-09-21 04:30:00
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "60 days 18 hours 30 minutes ", CalendarUtilities.duration( startDate, endDate));

        // Before leap day: 184 days 14 hours 25 minutes
        calendar.set( 2011, 6, 22, 9, 34, 18);   // 2011-07-22 09:34:18
        startDate = new Timestamp( calendar.getTimeInMillis());
        calendar.set( 2012, 0, 22, 23, 59, 59);  // 2012-01-22 23:59:59
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "184 days 14 hours 25 minutes ", CalendarUtilities.duration( startDate, endDate));

        // Over a leap day: 183 days 8 hours 1 minute
        calendar.set( 2011, 9, 8, 15, 58, 44);  // 2011-10-08 15:58:44
        startDate = new Timestamp( calendar.getTimeInMillis());
        calendar.set( 2012, 3, 8, 23, 59, 59);  // 2012-04-08 23:59:59
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "183 days 8 hours 1 minute ", CalendarUtilities.duration( startDate, endDate));

        // One year
        calendar.set( 2012, 9, 8, 23, 59, 59);  // 2012-10-08 23:59:59
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "1 year 8 hours 1 minute ", CalendarUtilities.duration( startDate, endDate));

        // Several years
        calendar.set( 2017, 5, 22, 15, 0, 0);  // 2017-06-22 15:00:00
        endDate = new Timestamp( calendar.getTimeInMillis());
        assertEquals( "5 years 256 days 23 hours 2 minutes ", CalendarUtilities.duration( startDate, endDate));
    }

    @Test
    public void calenderDurationTests() {

        // A minute difference
        Calendar startCalendar = Calendar.getInstance();
        Calendar endCalendar = Calendar.getInstance();
        startCalendar.set( 2011, 6, 22, 9, 34, 18);   // 2011-07-22 09:34:18
        endCalendar  .set( 2011, 6, 22, 9, 35, 18);   // 2011-07-22 09:35:18
        assertEquals( "1 minute ", CalendarUtilities.duration( startCalendar, endCalendar));

        // An hour and 45 minutes
        endCalendar.set( 2011, 6, 22, 11, 19, 59);  // 2011-07-22 11:19:59
        assertEquals( "1 hour 45 minutes ", CalendarUtilities.duration( startCalendar, endCalendar));

        // A day 8 hours and 30 minutes
        endCalendar.set( 2011, 6, 23, 18, 04, 59);  // 2011-07-23 18:04:59
        assertEquals( "1 day 8 hours 30 minutes ", CalendarUtilities.duration( startCalendar, endCalendar));

        // 60 days 18 hours and 30 minutes
        endCalendar.set( 2011, 8, 21, 4, 04, 0);   // 2011-09-21 04:30:00
        assertEquals( "60 days 18 hours 30 minutes ", CalendarUtilities.duration( startCalendar, endCalendar));

        // Before leap day: 184 days 14 hours 25 minutes
        startCalendar.set( 2011, 6, 22, 9, 34, 18);   // 2011-07-22 09:34:18
        endCalendar  .set( 2012, 0, 22, 23, 59, 59);  // 2012-01-22 23:59:59
        assertEquals( "184 days 14 hours 25 minutes ", CalendarUtilities.duration( startCalendar, endCalendar));

        // Over a leap day: 183 days 8 hours 1 minute
        startCalendar.set( 2011, 9, 8, 15, 58, 44);  // 2011-10-08 15:58:44
        endCalendar  .set( 2012, 3, 8, 23, 59, 59);  // 2012-04-08 23:59:59
        assertEquals( "183 days 8 hours 1 minute ", CalendarUtilities.duration( startCalendar, endCalendar));

        // One year
        endCalendar.set( 2012, 9, 8, 23, 59, 59);  // 2012-10-08 23:59:59
        assertEquals( "1 year 8 hours 1 minute ", CalendarUtilities.duration( startCalendar, endCalendar));

        // Several years
        endCalendar.set( 2017, 5, 22, 15, 0, 0);  // 2017-06-22 15:00:00
        assertEquals( "5 years 256 days 23 hours 2 minutes ", CalendarUtilities.duration( startCalendar, endCalendar));
    }

    @After
    public void tearDown() {}
}
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/calendar-and-timestamp-duration-determination-method-in-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>File Drag and Drop onto a Google Web Toolkit Application &#8211; Outdated</title>
		<link>http://www.colabrativ.com/drag-and-drop-onto-a-google-web-toolkit-application-utdated/</link>
		<comments>http://www.colabrativ.com/drag-and-drop-onto-a-google-web-toolkit-application-utdated/#comments</comments>
		<pubDate>Sat, 30 Apr 2011 22:11:21 +0000</pubDate>
		<dc:creator>Marc Whitlow</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[drag & drop]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[iExperiment]]></category>

		<guid isPermaLink="false">http://www.colabrativ.com/?p=18</guid>
		<description><![CDATA[Users increasingly expect to be able to drag and drop objects in applications, including web applications. I would like to show you how we recently added the ability to drop files on to our enterprise electronic notebook iExperiment. iExperiment&#8217;s client &#8230; <a href="http://www.colabrativ.com/drag-and-drop-onto-a-google-web-toolkit-application-utdated/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Users increasingly expect to be able to drag and drop objects in applications, including web applications.  I would like to show you how we recently added the ability to drop files on to our enterprise electronic notebook iExperiment. iExperiment&#8217;s client side is built on Google Web Toolkit (GWT).  GWT currently does not support file drag and drop. </p>
<p>The work flow for file drag and drop is as follows: </p>
<ol>
<li>The user drops a file on to the client.</li>
<li>The client sends the drop element id and the file to the server in a multipart POST for storage and analysis.</li>
<li>The server sends back the POST response to the client with information on how to display the dropped file.</li>
<li>The client presents the upload file&#8217;s information to the user.</li>
</ol>
<p>The file drop event is handled by adding &#8220;ondrop&#8221; attribute to the HTML elements.  The &#8220;ondrop&#8221; attribute calls the droppedFile Javascript routine that creates and sends an HTTP POST request to the server. Note, that the first argument in the droppedFile Javascript call is an &#8220;element-id&#8221;, and the event as the second argument.  The drop element ID allows us to identify where the file was drop on the page.</p>
<div class="codeBox">
<strong>Example of &#8220;ondrop&#8221; Attribute in an HTML Table Element</strong></p>
<pre>&lt;table ondrop="event.stopPropagation();
               event.preventDefault();
               droppedFile('element-id', event);"&gt;</pre>
</div>
<p>The &#8220;ondrop&#8221; element is created by the static addOnDrop method in a client side class (DropFileConnector). </p>
<div class="codeBox">
<strong>addOnDrop Method</strong></p>
<pre>
/** Add a ondrop attribute to an element in the DOM, example:
 * ondrop="event.stopPropagation(); droppedFile('element-id', event);"
 *
 * @param element DOM element
 * @param elementID Element Id to be sent to droppedFile joutine.
 */
public static void addOnDrop(Element element, String elementID) {
    element.setAttribute("ondrop",
        "event.stopPropagation(); droppedFile(\'" + elementID + "\', event);");
}
</pre>
</div>
<p>The droppedFile Javascript routine creates a multipart HTTP POST request.  On lines 6-9 the information needed for the POST is gathered and created, including the URL, files and boundary.  The XMLHttpRequest is created on line 10 and upload progress monitoring is set up in lines 12-14.  The POST is created on lines 16-35 and sent on line 43.  The first part of the POST contains the element Id (dropElementID) and the subsequent parts (lines 26-33) contain the files that were drop on the page.  Note, that a binary file get <code>.getAsBinary()</code> is used on line 32. </p>
<p>The POST responses are handled by the request.onreadystatechange function on line 37-51, and are sent to the client through <code>window.top.dropFileListener.droppedFile( );</code> calls on lines 45 and 49.  Initially (<code>readyState == 1</code>) the file name being uploaded along with the MIME boundary are sent to the client on lines 39-46.  After succesful completion of the POST (<code>readyState == 4</code>), the POST response is forward to the GWT application.</p>
<div class="codeBox">
<strong>droppedFile Javascript Routine</strong></p>
<pre>
01  var boundary = null;
02
03  function droppedFile(dropElementID, event) {
04      if( window.top.dropFileListener ) {
05          if (event.dataTransfer) {
06              var url = secureURL + "upload";
07              var token = document.cookie.substring( 26, document.cookie.indexOf("userName") - 12);
08              var files = event.dataTransfer.files;
09              boundary = "BoUnDaRy_._-_._-_._" + Math.floor(999999999999999 * Math.random());
10              var request = new XMLHttpRequest();
11
12              request.upload.onprogress = updateProgress;
13              request.upload.onload 	  = loaded;
14              request.upload.onerror 	  = loadError;
15
16              request.open("POST", url, true); // open asynchronous post
17              request.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
18              request.setRequestHeader("Session-Token", token);
19
20              var postContent = "--" + boundary + "\r\n" +
21                  "Content-Disposition: info; name=\"drop-element-id\"\r\n" +
22                  "\r\n" +
23                  dropElementID + "\r\n" +
24                  "--" + boundary;
25
26              for (var i = 0; i &lt; files.length; i++) {
27                  postContent = postContent + &quot;\r\n&quot; +
28                      &quot;Content-Disposition: file; name=\&quot;file\&quot;; filename=\&quot;&quot; + files[i].name + &quot;\&quot;\r\n&quot; +
29                      &quot;Content-Type: application/xml\r\n&quot; +
30                      &quot;File-Length: &quot; + files[i].size + &quot;\r\n&quot; +
31                      &quot;\r\n&quot; +
32                      files[i].getAsBinary() + &quot;\r\n&quot; +
33                      &quot;--&quot; + boundary;
34              }
35              postContent = postContent + &quot;--\r\n&quot;;
36
37              request.onreadystatechange = function() {
38                  if(this.readyState == 1) {
39                      var filesJSON = &#039;&quot;files&quot;:[&#039;;
40                      for (var i = 0; i &lt; files.length; i++) {
41                          filesJSON = filesJSON + &#039;&quot;&#039; + files[i].name + &#039;&quot;&#039;;
42                          if (i &lt; files.length - 1) filesJSON = filesJSON + &#039;, &#039;;
43                      }
44                      filesJSON = filesJSON + &#039;]&#039;
45                      window.top.dropFileListener.droppedFile( &#039;{&#039; +
46                          &#039;&quot;requestBoundary&quot;: &quot;&#039; + boundary + &#039;&quot;, &#039; + filesJSON + &#039;}&#039;);
47                  }
48                  if(this.readyState == 4) {
49                      window.top.dropFileListener.droppedFile( request.responseText );
50                  }
51              }
62
53              request.sendAsBinary(postContent);
54          }
55          else {
56              alert(&quot;Your browser does not support file drag and drop. &quot; +
57                      &quot;We recommend that upgrade your browser to one that support HTML5, &quot; +
58                      &quot;such as Mozella&#039;s FireFox or Apple&#039;s Safari or Google&#039;s Chrome.&quot;);
59          }
60      }
61      else {
62          alert(&quot;window.top.dropFileListener not found!&quot;);
63      }
64  }
</pre>
</div>
<p>The DropFileConnector class connects the dropFileListener in the Javascript to the GWT code. DropFileConnector class has a ClientSideDropFileSupport interface that defines the droppedFile method in the JavaScript.  theObserver is a static ClientSideDropFileSupport incidence that connects to Javascript droppedFile method to ClientSideDropFile&#8217;s droppedFile method. </p>
<div class="codeBox">
<strong>DropFileConnector class</strong></p>
<pre>
package com.colabrativ.common.client; 

import com.google.gwt.dom.client.Element; 

public class DropFileConnector {
    /** Used to pass information to the GWT application. Register your implementations with
     *  {@link com.colabrativ.common.client.DropFileConnector#connect( ClientSideDropFileSupport)}
     */
    public interface ClientSideDropFileSupport {
        /** The page calls this method to send dropped file information to application
         *
         * @param json JSON string containing the file name information.
         */
        void droppedFile(String json);
    } 

    /** An observer of drop file events, supplied by the GWT application. */
    static private ClientSideDropFileSupport theObserver; 

    /**
     * Connect the GWT application to the drop file JavaScript. The observer is notified
     * whenever the user drops a file on the application area (id="app-area").
     *
     * @param observer
     */
    public static void connect( ClientSideDropFileSupport observer ) {
        theObserver = observer;
        connectToPanel();
    }

    // This method are "glue" methods that let the simple JNDI call talk to the observer through its interface.
    @SuppressWarnings("all")
    private static void droppedFile(String s) { theObserver.droppedFile(s); }

    private static native void connectToPanel() /*-{
        var listener = new Object();
        listener.droppedFile = function(json) {
            json = unescape( json );
            @com.colabrativ.common.client.DropFileConnector::droppedFile( Ljava/lang/String;)( json );
        };

        $wnd.top.dropFileListener = listener;
    }-*/; 

    /**
     * Add a ondrop attribute to an element in the DOM, example:
     * ondrop="event.stopPropagation(); droppedFile('element-id', event);"
     *
     * @param element DOM element
     * @param elementId Element Id to be sent to droppedFile routine.
     */
    public static void addOnDrop(Element element, String elementId) {
        element.setAttribute("ondrop",
            "event.stopPropagation(); droppedFile(\'" + elementId + "\', event);");
    }
}
</pre>
</div>
<p>Finally, a <code>DropFileConnector.connect</code> call is made in a client class that handles the POST responses.  Our upload servlet adds either a OKAY or a FAIL to the POST response that the DropFileConnector handles.  In our implementation the POST responces are encapsulated in JSON.  The upload progress monitoring is also handled by the DropFileConnector.  In our implementation the MIME boundary is used as an Id for the upload, and the monitoring is managed by the singleton of the UploadManager class.</p>
<div class="codeBox">
<strong>DropFileConnector Connection</strong></p>
<pre>
DropFileConnector.connect
(
    new DropFileConnector.ClientSideDropFileSupport() {
        public void droppedFile(String response) {
            if (response.startsWith("OKAY:")) {
                String json = response.substring( response.indexOf(": ") + 2); // Remove OKAY:
                determineWhatToDoWithResponse(json);
            }
            else if (response.startsWith("FAIL:")) {
                // Do Nothing?
            }
            else {
            	JSONObject responseJSON = (JSONObject) JSONParser.parseStrict( response );
                JSONString boundaryJSON = (JSONString) responseJSON.get( UploadResponse.requestBoundary);

                if (boundaryJSON != null) {
                    String boundary = boundaryJSON.toString();
                    JSONArray filesJSON = (JSONArray) responseJSON.get( UploadResponse.files);

                    if (filesJSON != null) {
                        UploadManager.getInstance().addProgressDialog( boundary, filesJSON);
                    }
                    else {
                        UploadManager.getInstance().update( boundary, responseJSON);
                    }
                }
            }
        }
    }
);
</pre>
</div>
<p>Several resources helped us create our file drag and drop; these included: </p>
<ol>
<li>Box.net and html5 drag and drop blog by Christopher Blizzasrd at <a href="http://hacks.mozilla.org/2010/06/html5-adoption-stories-box-net-and-html5-drag-and-drop/">http://hacks.mozilla.org/2010/06/html5-adoption-stories-box-net-and-html5-drag-and-drop/</a></li>
<li>Mozilla&#8217;s developers Network page on Using XMLHttpRequest <a href="https://developer.mozilla.org/En/Using_XMLHttpRequest">https://developer.mozilla.org/En/Using_XMLHttpRequest</a></li>
<li>XHR progress and rich file upload feedback by Austin King at <a href="http://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/">http://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/</a>	</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colabrativ.com/drag-and-drop-onto-a-google-web-toolkit-application-utdated/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
