<?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>Adam Franco.com &#187; Work</title>
	<atom:link href="http://www.adamfranco.com/archives/category/work/feed" rel="self" type="application/rss+xml" />
	<link>http://www.adamfranco.com</link>
	<description>Musings, projects, software, and photography.</description>
	<lastBuildDate>Tue, 09 Mar 2010 14:07:19 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Importing users into Bugzilla</title>
		<link>http://www.adamfranco.com/archives/374</link>
		<comments>http://www.adamfranco.com/archives/374#comments</comments>
		<pubDate>Tue, 09 Mar 2010 04:11:45 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Bugzilla]]></category>
		<category><![CDATA[import]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=374</guid>
		<description><![CDATA[For the past 6 months our Web Application Development work-group has been Bugzilla as our issue tracker with quite a bit of success. While it has its warts, Bugzilla seems like a pretty decent issue-tracking system and is flexible enough to fit into a variety of different work-flows. One very important feature of Bugzilla is [...]]]></description>
			<content:encoded><![CDATA[<p>For the past 6 months our <a href="http://go.middlebury.edu/webservices">Web Application Development work-group</a> has been Bugzilla as our issue tracker with quite a bit of success. While it has its warts, Bugzilla seems like a pretty decent issue-tracking system and is flexible enough to fit into a variety of different work-flows. One very important feature of Bugzilla is support for LDAP authentication. This enables any Middlebury College user to log in and report a bug using their standard campus credentials. </p>
<p>While LDAP authentication works great, there is one problem: If a person has never logged into our Bugzilla, we can&#8217;t add them to the CC list of an issue. This is important for us because issues usually don&#8217;t get submitted directly to the bug tracker, but rather come in via calls, emails, tweets, and face-to-face meetings. We are then left to submit issues to Bugzilla ourselves to keep track of our to-do items. Ideally we&#8217;d add the original reporter to the bug&#8217;s CC list so that they will automatically be notified as we make progress on the issue, but their Bugzilla account must exist before we can add them to the bug.</p>
<p>Searching about the internet I wasn&#8217;t able to find anything about how to import LDAP users (or any kind of users) into Bugzilla, though I was able to find some <a href="http://groups.google.com/group/mozilla.support.bugzilla/browse_thread/thread/165d4fc1a8b4ad82/b1e31ad20bfef3f0">basic instructions</a> on how to create a single user via Bugzilla&#8217;s Perl API. To improve on the lack of user-import support I&#8217;ve created an Perl script that creates users from lines in a tab-delimited text file (<code>create_users.pl</code>) as well as a companion PHP script that will export an appropriately-formatted list of users from an Active Directory (LDAP) server (<code>export_users.php</code>).</p>
<p><span id="more-374"></span><br />
<a href='http://www.adamfranco.com/wp-content/uploads/2010/03/BugzillaImport.zip'>BugzillaImport.zip</a> &#8212; Unzip in your Bugzilla directory, run via the command line. See below for examples.</p>
<h1>File Listings:</h1>
<h2>create_users.pl</h2>
<p>This script can safely be run repeatedly. Only new users not already in Bugzilla will be added, users matching existing email addresses will be skipped.</p>
<pre>#!/usr/bin/env perl
##########################################################
# This is a basic script to import users into Bugzilla.
#
# Users can be imported from tab-delimited text files or
# tab-delimited lines piped to STDIN. Lines should have 3
# columns: login	email	name
#
#
# Author:
#	Adam Franco (afranco@middlebury.edu)
# Date:
#	2010-03-08
# URL:
#	http://www.adamfranco.com/archives/374
# License:
#   The contents of this file are subject to the Mozilla Public
#   License Version 1.1 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.mozilla.org/MPL/
#
#   Software distributed under the License is distributed on an "AS
#   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
#   implied. See the License for the specific language governing
#   rights and limitations under the License.
##########################################################

use FindBin qw($Bin);
BEGIN {
    push @INC,$Bin;
    push @INC,$Bin."/lib";
    push @INC,$Bin."/lib/x86_64-linux-thread-multi";
}
use Bugzilla;
use Bugzilla::User;
use Error qw(:try);

sub usage {
    print "
Usage:
    $0 ListOfUsers1.txt [ListOfUsers2.txt [...]]
    $0 < ListOfUsers.txt

The ListOfUsers can be passed as either a file argument or passed to STDIN.

The ListOfUsers must be tab-delimited with the following columns:
login   email   name

";
    exit 1;
}

foreach (@ARGV) {
    if ($_ =~ /^-h|--help$/) {
        usage();
    }
}

my $lines = 0;
my $users = 0;
my $usersAdded = 0;
while (<>) {
    chomp; # Remove the trailing new-line.
    my($login, $email, $name) = split(/\t/, $_);

    if ($login &#038;&#038; $email &#038;&#038; $name &#038;&#038; $login =~ /[a-z0-9]+/ &#038;&#038;  $email =~ /[a-z0-9]+.*@.*[a-z0-9]+/ &#038;&#038; $name =~ /[a-z]+/) {
        if (is_available_username($email)) {
            try {
                my $user = Bugzilla::User->create({
                    login_name    => $email,
                    realname      => $name,
                    cryptpassword => '*',
                    disable_mail  => 0,
                    extern_id     => $login
                });
                print "Account for " . $user->login . " was created.\n";
                $usersAdded++;
            } catch Error with {
                my $ex = shift;
                my $error = "Error: $ex";
                $error =~ s/\n|\r/ /g;
                print $error."\n";
            };
        }

        $users++;
    }
    $lines++;
    close (ARGV) if (eof);
}

if (!$lines) {
    print "No input lines given.\n\n";
    usage();
}

print "\n$lines lines evaluated, $users user records checked, $usersAdded users added.\n";

exit 0;
</pre>
<h2>export_users.php</h2>
<pre>#!/usr/bin/env php
&lt;?php
##########################################################
# This is a basic script to export users from an
# MS Active Directory via LDAP in the format required
# by create_users.pl.
#
# Authors:
#	Adam Franco (afranco@middlebury.edu)
#	Ian McBride (imcbride@middlebury.edu)
# Date:
#	2010-03-08
# URL:
#	http://www.adamfranco.com/archives/374
# License:
#   The contents of this file are subject to the Mozilla Public
#   License Version 1.1 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.mozilla.org/MPL/
#
#   Software distributed under the License is distributed on an "AS
#   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
#   implied. See the License for the specific language governing
#   rights and limitations under the License.
##########################################################

$ldaphost = "ldap.example.com";
$ldapport = 389;
$ldapuser = "username";
$ldappass = "password";
$baseDN = "DC=example,DC=com";

$connection = ldap_connect($ldaphost, $ldapport);

if (!$connection) die();

if (ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION,3) === FALSE) die();

if (ldap_set_option($connection, LDAP_OPT_REFERRALS,0) === FALSE) die();

$bind = ldap_bind($connection, $ldapuser, $ldappass);

if (!$bind) die();

$filter = "(&#038;(objectClass=User)(!(objectClass=Computer)))";

$search = ldap_search($connection, $baseDN, $filter, array("samaccountname", "mail", "givenname", "sn"));

$entries = ldap_get_entries($connection, $search);

print "samaccountname\temail\tname\n";

foreach($entries as $entry) {
  if(isset($entry['samaccountname'])) {
    print iconv('UTF-8', 'UTF-8//IGNORE', $entry['samaccountname'][0]);
  }
  print "\t";

  if(isset($entry['mail'])) {
    print iconv('UTF-8', 'UTF-8//IGNORE', $entry['mail'][0]);
  }
  print "\t";

  $name = '';
  if(isset($entry['givenname'])) {
    $name .= iconv('UTF-8', 'UTF-8//IGNORE', $entry['givenname'][0]);
  }  $name .= ' ';
  if(isset($entry['sn'])) {
    $name .= iconv('UTF-8', 'UTF-8//IGNORE', $entry['sn'][0]);
  }
  print trim($name);

  print "\n";
}
</pre>
<h1>Example Usage</h1>
<p>After unzipping the scripts in your Bugzilla directory you can use the <code>create_users.pl</code> script right away. To use <code>export_users.php</code> you will need to edit it and add your LDAP server configuration.<br />
<code>[root@hostname /var/www/htdocs/bugzilla/]# ./export_users.php | ./create_users.pl</code></p>
<p>If you&#8217;d rather import users from another source, simply create one or more tab-delimited text files that have the following columns:<br />
login&nbsp;&nbsp;&nbsp;&nbsp;email&nbsp;&nbsp;&nbsp;&nbsp;name<br />
<code>[root@hostname /var/www/htdocs/bugzilla/]# ./create_users.pl users.txt otherusers.txt</code></p>
<p>You can pipe tab-delimited data to the script as well:<br />
<code>[root@hostname /var/www/htdocs/bugzilla/]# head -n 20 users.txt | ./create_users.pl</code></p>
<h2>Update:</h2>
<ul>
<li>Changed the license statement to the MPL be compatible with the rest of Bugzilla</li>
<li>Changed the password to &#8216;*&#8217; based on Max&#8217;s suggestion</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/374/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>High-availability Drupal &#8212; File-handling</title>
		<link>http://www.adamfranco.com/archives/266</link>
		<comments>http://www.adamfranco.com/archives/266#comments</comments>
		<pubDate>Wed, 09 Sep 2009 21:18:27 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=266</guid>
		<description><![CDATA[One of the requirements in the migration of our web sites to Drupal is that we create a robust and redundant platform that can stay running or degrade gracefully when hardware or software problems inevitably arise. While our sites get heavy use from our communities and the public, our traffic numbers are no where near [...]]]></description>
			<content:encoded><![CDATA[<p>One of the requirements in the migration of our <a href="http://www.middlebury.edu/">web</a> <a href="http://www.miis.edu">sites</a> to <a href="http://drupal.org/">Drupal</a> is that we create a robust and redundant platform that can stay running or degrade gracefully when hardware or software problems inevitably arise. While our sites get heavy use from our communities and the public, our traffic numbers are no where near those of a top-1000 site and could comfortably run off of one machine that ran both the database and web-server.<br />
<div id="attachment_297" class="wp-caption aligncenter" style="width: 541px"><img src="http://www.adamfranco.com/wp-content/uploads/2009/09/1-SingleMachine.jpg" alt="Single Machine Configuration" title="Single Machine Configuration" width="531" height="332" class="size-full wp-image-297" /><p class="wp-caption-text">Single Machine Configuration</p></div><br />
This simple configuration however has the major weakness that any hiccups in the hardware or software of the machine will likely take the site offline until the issues can be addressed. In order to give our site a better chance at staying up as failures occur, we separate some of the functional pieces of the site onto discrete machines and then ensure that each function is redundant or fail-safe. This post and the next will detail a few of the techniques we have used to build a robust site.</p>
<p><span id="more-266"></span></p>
<h2>Pull out the database, use multiple web-servers</h2>
<p>The two main components of Drupal (and most similar web applications) are the webserver, which handles PHP execution and file-serving; and the MySQL database, which stores all data with the exception of uploaded files. By putting the database on a separate machine we can can have multiple machines acting as front-end web-servers, both of them reading and writing to the same database. In this way, it doesn&#8217;t matter which web-server handles a given request as they will both get the same information out of the database. With two or more web-servers, our platform gains some redundancy since one web-server can fail while the second keeps handling requests.</p>
<p>With both web-servers point at the same database server, the database server still remains a single point of failure. Database clustering can alleviate this problem, but will be the subject of a future post.</p>
<h2>Multiple web-server challenges</h2>
<p>This redundancy does come at a cost in complexity however, since we need to ensure that any uploaded files are available on both web-servers. There seem to be <a href="http://groups.drupal.org/node/1648">two primary ways</a> of tackling this problem (without resorting to costly and complex distributed file-system tools). The first is use rsync to copy files between the web-servers every few minutes.<br />
<div id="attachment_299" class="wp-caption aligncenter" style="width: 610px"><img src="http://www.adamfranco.com/wp-content/uploads/2009/09/2a-Two-Web-servers-rsync.jpg" alt="Two web servers with rsync" title="2a - Two Web servers - rsync" width="600" class="size-full wp-image-299" /><p class="wp-caption-text">Two web servers with rsync</p></div><br />
While this is reasonably simple to set up between two web-servers, it comes with significant downsides:</p>
<ul>
<li>Files cannot be deleted in the sync as newly-added files will exist on only one web-server. Since the sync is two-way, there is no way for the rsync processes to tell the difference between a new file and a deleted file.</li>
<li>Requests that come to the &#8220;other&#8221; web-server will not be able to access new files until the sync happens.</li>
<li>If additional web-servers are added, the sync process needs to be updated on every existing web-server to include the new web-server</li>
</ul>
<p>The other alternative is to store uploaded files on a separate file-server, whose upload directory is mounted on each web-server using NFS. This method eliminates the synchronization problems, since all web-servers are essentially writing to the same directory.<br />
<div id="attachment_300" class="wp-caption aligncenter" style="width: 610px"><img src="http://www.adamfranco.com/wp-content/uploads/2009/09/2b-Two-Web-servers-nfs.jpg" alt="Two web servers with NFS" title="2b - Two Web servers - nfs" width="600" class="size-full wp-image-300" /><p class="wp-caption-text">Two web servers with NFS</p></div><br />
On top of the complexity of adding a fourth machine (the file-server) to our mix, this method also leaves us with the file-server as a single point of failure &#8212; were it to go down, no uploaded files would be accessible.</p>
<h2>Best of both worlds</h2>
<p>In order to better solve this problem, the approach we took is to go the NFS route, but augment it with a backup copy of the files stored on the local file-system of each web-server. Every ten minutes or so a script (<a href='http://www.adamfranco.com/wp-content/uploads/2009/09/sync_files.sh'>sync_files.sh</a>) runs that checks to see if the shared NFS directory is available, and if so syncs the uploaded-files to a backup location on the web-server&#8217;s file-system. This backup copy has its permissions set so that the Apache process cannot write to it, preventing synchronization problems if the shared NFS directory goes offline and we need to serve files out of the backup copy.<br />
<div id="attachment_302" class="wp-caption aligncenter" style="width: 610px"><img src="http://www.adamfranco.com/wp-content/uploads/2009/09/3-Two-Web-servers-nfs+backup1.jpg" alt="Two web servers with NFS and local backup copies." title="3 - Two Web servers - nfs+backup" width="600" class="size-full wp-image-302" /><p class="wp-caption-text">Two web servers with NFS and local backup copies.</p></div><br />
A second script (<a href='http://www.adamfranco.com/wp-content/uploads/2009/09/check_link.sh'>check_link.sh</a>) runs every minute and checks to see if the shared NFS directory is available. If it is offline, this script changes the symbolic link of our &#8220;files&#8221; directory so that Drupal will now use the read-only backup copy for its files. If the NFS directory comes back online, this script will again update the symbolic link to point at our writable shared NFS directory.</p>
<p>An important consideration in this setup is that the NFS share is mounted in &#8217;soft&#8217; mode so that file-access errors will time out quickly and allow for a timely switch-over to our backup files.<br />
<div class="wp-caption alignnone" style="width: 610px">
<pre>files.example.edu:/images       /mnt/files     nfs     soft    0 0</pre>
<p><p class="wp-caption-text">An example 'soft' mount line in /etc/fstab</p></div></p>
<p>If the default &#8216;hard&#8217; NFS mount is used, the check_link processes will hang indefinitely while trying to communicate with the file-server and never switch to our backup files. </p>
<p>Here is an example layout on the web-server to accomplish this setup:</p>
<pre style='width: 100%'># The scripts that will be run by cron:
/usr/local/bin/check_link.sh  # Run every minute
/usr/local/bin/sync_files.sh   # Run every 10 minutes

# The mounted NFS share:
/mnt/files/

# The backup copy of files:
/srv/files_read_only/

# The 'files' symbolic link, pointing normally at the NFS share:
/srv/files/ => /mnt/files/
# On NFS failure, this link will be switched to the backup directory:
/srv/files/ => /srv/files_read_only/

# The Drupal code directory:
/srv/drupal/
# The files directory for a site is a link into the switched files link
/srv/drupal/sites/www.example.com/files/ => /srv/files/www.example.com/files/
</pre>
<p>By mounting the shared NFS directory, keeping a read-only local copy of the files, and monitoring the state of the NFS directory we gain the following benefits:</p>
<ul>
<li>No problems with synchronization as all web-servers share the same remote filesystem.</li>
<li>Synchronization of the local backup copies is not a problem as this is always a one-way sync rather than a two-way sync between different web-servers.</li>
<li>While the NFS file-server is still a single point of failure, read access to the uploaded files (via the backup copy) will be restored after a maximum of one minute plus the NFS time-out (2 minutes by default for &#8217;soft&#8217; mounts).</li>
<li>The web-servers don&#8217;t need to know about each other, easing configuration if additional web-servers are added.</li>
</ul>
<p>This configuration adds an extra machine to the platform mix and a bit of complexity, but it makes normal operation robust (instant file availability to all web-servers) and allows for graceful degradation (file-access becomes read-only) if the file-server goes down.</p>
<p><em>Many thanks to our system administrator, Mark Pyfrom, for all of his help in developing and testing this platform.</em></p>
<p><em>* Update on 2009-09-10: added note about &#8217;soft&#8217; NFS mounts and an example file-system layout.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/266/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Setting up CAS development on OS X</title>
		<link>http://www.adamfranco.com/archives/146</link>
		<comments>http://www.adamfranco.com/archives/146#comments</comments>
		<pubDate>Fri, 19 Jun 2009 20:57:12 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[CAS]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Single Sign On]]></category>
		<category><![CDATA[Tomcat]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=146</guid>
		<description><![CDATA[Central Authentication Service (CAS) is a single-sign-on system for web applications written in Java that we have begun to deploy here at Middlebury College. Web applications communicate with it by forwarding users to the central login page and then checking the responces via a web-service protocol.
A few months ago Ian and I got CAS installed [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jasig.org/cas/">Central Authentication Service (CAS)</a> is a single-sign-on system for web applications written in Java that we have begun to deploy here at Middlebury College. Web applications communicate with it by forwarding users to the central login page and then checking the responces via a web-service protocol.</p>
<p>A few months ago Ian and I got CAS installed on campus and began updating applications to work with it rather than maintaining their own internal connections to the Active Directory server. Throughout this process we ran into a few challenges (such as returning attributes with the authentication-success response) and a bug in CAS, but we worked through these and got CAS up and running successfully.</p>
<p>We are now at a point where we need to do some customizations to our CAS installation to deal with changes to the group structure in the Active Directory. As well, the bug I reported was apparently fixed in a new CAS version, an improvement I need to test before we update our production installation. Both of these require a bit more poking at CAS than we can do safely in our production environment, so I am now embarking on the process of setting up a Java/Tomcat development environment on my PC. I&#8217;m documenting this process here both for my own benefit (when I have to set this up again on my laptop) and in case it helps anyone else. </p>
<p>Read on for my step-by-step instructions for setting up a CAS development environment on OS X.<br />
<span id="more-146"></span></p>
<p>Since I&#8217;ve recently been successful using <a href="http://www.macports.org/">MacPorts</a> to install <a href="http://git-scm.com/">Git</a> (a source-code-management too), I decided to use MacPorts to install <a href="http://tomcat.apache.org/">Apache Tomcat</a>, <a href="http://maven.apache.org/">Maven</a>, and the other required software.</p>
<h1>Part One: Get a default CAS installation up and running</h1>
<h2>Install the Apache Tomcat server using MacPorts </h2>
<pre>sudo port install tomcat5</pre>
<p>A number of packages will not be successfully found by ports, resulting in the following error:</p>
<pre>--->  Verifying checksum(s) for servlet24-api
Error: Checksum (md5) mismatch for apache-tomcat-5.5.25-src.tar.gz
Error: Target org.macports.checksum returned: Unable to verify file checksums</pre>
<p>The easiest fix I found was do go to the apache website and directly download the file. <a href="http://www.google.com/search?q=apache-tomcat-5.5.25-src.tar.gz">Googling</a> will find it. Once you&#8217;ve downloaded the file, find the corrupted one on your file-system with</p>
<pre>find /opt/local/var/macports -name "apache-tomcat-5.5.25-src.tar.gz"</pre>
<p>And replace the corrupted version with the directly downloaded one and then re-try installation with MacPorts:</p>
<pre>sudo mv /Users/afranco/Downloads/apache-tomcat-5.5.25-src.tar.gz /opt/local/var/macports/distfiles/servlet24-api/</pre>
<p>You will have to do this process several times for different packages that fail to download.</p>
<p>You will likely also need to install the <a href="http://dev.mysql.com/downloads/connector/j/3.1.htmll">mysql-connector-java</a>. Download the zip archive and copy the .jar file inside to <code>/Library/Java/Extensions/</code></p>
<h2>Install Maven</h2>
<p>Same thing as with Tomcat, try installing with ports and replace failed downloads.</p>
<pre>sudo port install maven2</pre>
<p>Also, make sure that <code>/opt/loca/bin/</code> is to the front of the search path in your <code>~/.bash_profile</code>. If not, the built-in mvn command may take precedence.</p>
<pre>mvn -v
Apache Maven 2.1.0</pre>
<h2>Download CAS</h2>
<p>I cloned the repository using Git so that I can easily maintain my private branches, but you can download it directly or checkout with subversion.</p>
<pre>git-svn clone  https://www.ja-sig.org/svn/cas-clients/phpcas/ --trunk=trunk --branches=branches --tags=tags</pre>
<h2>Build CAS</h2>
<p>Building CAS is accomplished by cd&#8217;ing to the directory in which you downloaded CAS and runing:</p>
<pre>mvn package install</pre>
<p>Because some of the tests rely on network particulars, I can&#8217;t get the build to work unless I skip tests by instead using:</p>
<pre>mvn -Dmaven.test.skip=true package install</pre>
<h2>Install CAS</h2>
<p>Copy the CAS war and files to the Tomcat webapps directory:</p>
<pre>sudo cp -R cas-server-webapp/target/cas-server-webapp-3.x.x  /opt/local/share/java/tomcat5/webapps/cas
sudo cp -R cas-server-webapp/target/cas.war  /opt/local/share/java/tomcat5/webapps/cas.war</pre>
<h2>Start Tomcat/CAS</h2>
<p>Start Tomcat:</p>
<pre>sudo tomcatctl start</pre>
<p>Point your browser at <a href="http://localhost:8080/cas/">http://localhost:8080/cas/</a> and you should see the CAS login page.</p>
<h1>Part Two: Customizing CAS</h1>
<h2>Create the customization overlay</h2>
<p>Following the <a href="http://www.ja-sig.org/wiki/display/CASUM/Maintaining+local+customizations+using+Maven+2">instructions for maintaining local customizations</a> on the CAS wiki, I created a <code>cas-server-midd</code> subdirectory in my CAS-source directory and added a <code>pom.xml</code> file based on the example. Running maven properly generates a war file:</p>
<pre>cd cas3/cas-server-midd/

mvn -Dmaven.test.skip=true package install

ls target/
	cas
	cas-server-midd-3.3.3-SNAPSHOT
	cas-server-webapp-3.3.3-SNAPSHOT
	cas.war
	maven-archiver
	pom-transformed.xml
	war

sudo rm -R  /opt/local/share/java/tomcat5/webapps/cas

sudo cp -R target/cas  /opt/local/share/java/tomcat5/webapps/cas

sudo cp target/cas.war  /opt/local/share/java/tomcat5/webapps/cas.war

sudo tomcatctl restart
</pre>
<p>Note that there is a <code>target/cas/</code> directory in addition to <code>target/cas-server-midd-3.x.x</code> and <code>target/cas-server-webapp-3.x.x</code> directories. In this case, the <code>target/cas/</code> one is the one we want to copy to the <code>tomcat5/webapps</code> directory. Refreshing your browser should still show the login page an not an error.</p>
<h2>Adding Customizations</h2>
<p>With the overlay directory structure in place, any files you add to the overlay directory (in my case <code>cas3/cas-server-midd/src/...</code>) will be used instead of the versions in <code>cas3/cas-server-webapp/src/...</code></p>
<p>Using the overlay has the same result as editing the files in <code>cas3/cas-server-webapp/src/...</code>, but keeps the changes in their own directory structure and allows the overlay to only contain files with modifications. All other files have their defaults used.</p>
<h2>Build and Install the customizations</h2>
<p>Run the maven build process again and copy the result from our overlay target to the Tomcat directory:</p>
<pre>cd cas3/cas-server-midd/
mvn -Dmaven.test.skip=true package install
sudo rm -R  /opt/local/share/java/tomcat5/webapps/cas
sudo cp -R target/cas  /opt/local/share/java/tomcat5/webapps/cas
sudo cp target/cas.war  /opt/local/share/java/tomcat5/webapps/cas.war
sudo tomcatctl restart
</pre>
<p>As you go, make more changes on the overlay and rebuild CAS. Lather, rinse, repeat.</p>
<p>Simply adding files to the overlay should be able to support any configuration or JSP (themes, etc) changes needed. I&#8217;ll make another post once I figure out where to put class-files for adding customized Principal-Resolver classes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/146/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Git Tip of the Day: Stage Hunks</title>
		<link>http://www.adamfranco.com/archives/91</link>
		<comments>http://www.adamfranco.com/archives/91#comments</comments>
		<pubDate>Tue, 13 Jan 2009 16:19:43 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Musings]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=91</guid>
		<description><![CDATA[One of the great things about the Git version-control system is the ability to incrementally commit your changes on a private branch to keep a step-by-step record of your thought and writing process on a fix or a feature, and then merge the completed work onto your main [or public] branch after your feature or [...]]]></description>
			<content:encoded><![CDATA[<p>One of the great things about the <a href="http://git-scm.com/">Git</a> version-control system is the ability to incrementally commit your changes on a <a href="http://amarok.kde.org/wiki/Development/Git#Branching">private branch</a> to keep a step-by-step record of your thought and writing process on a fix or a feature, and then merge the completed work onto your main [or public] branch after your feature or fix is all done and tested. By keeping an incremental log of your changes &#8212; rather than just committing one giant set of code with changes to 30 files &#8212; it becomes much easier to know why a certain line was changed in the future when bugs are discovered with it.</p>
<p>One thing that often happens to me though, is that I work for about a half hour to an hour trying to get a new piece of code working and in the process make several sets of changes to one file that are only loosely related. </p>
<p>Let&#8217;s say that I am fixing a bug in my &#8216;MediaLibrary&#8217; class and while doing so notice some some spelling mistakes in some comments that I fix. Now my one file has two changes my bug fix, and the spelling fix. Rather than committing both changes together with one comment describing both changes, I can highlight one of the changes in <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gui.html">git-gui</a> and select the &#8220;Stage Hunk for Commit&#8221; option.</p>
<p><a href='http://www.adamfranco.com/wp-content/uploads/2009/01/stagehunk1.jpg'><img src="http://www.adamfranco.com/wp-content/uploads/2009/01/stagehunk1.jpg" alt="Screen-shot of Staging a Hunk of code" title="Git-GUI: Stage Hunk" width="500" height="361" class="alignnone size-full wp-image-93" /></a></p>
<p>With that one hunk staged I can now commit with a message applicable to that change. Other changes can then be staged and committed with their own messages resulting in a very understandable history of changes.</p>
<p>&#8220;Stage Hunk for Commit&#8221; can also be used to commit important changes while not including debugging lines inserted in your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/91/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Outside-In:  Application Interoperability Using an OSID-Based Framework</title>
		<link>http://www.adamfranco.com/archives/76</link>
		<comments>http://www.adamfranco.com/archives/76#comments</comments>
		<pubDate>Thu, 26 Jun 2008 04:59:04 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Harmoni]]></category>
		<category><![CDATA[Segue]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=76</guid>
		<description><![CDATA[This post describes an interoperability demonstration given at OpeniWorld Europe 2008 in Lyon, France.
Abstract 
Segue and Concerto are two curricular applications built upon Harmoni, an Open Service Interface Definition-based (OSID) service-oriented application framework. This demonstration will show how website content created in Segue is stored as OSID Assets in Harmoni’s OSID Repository. Similarly, the demonstration [...]]]></description>
			<content:encoded><![CDATA[<p><em>This post describes an interoperability demonstration given at Open<span style='color: #a00'>i</span>World Europe 2008 in Lyon, France.</em></p>
<p><strong>Abstract </strong></p>
<p>Segue and Concerto are two curricular applications built upon Harmoni, an Open Service Interface Definition-based (OSID) service-oriented application framework. This demonstration will show how website content created in Segue is stored as OSID Assets in Harmoni’s OSID Repository. Similarly, the demonstration will show how multimedia assets created in Concerto can be stored  same repository. Interoperability will be demonstrated as each application is used to view and make real-time modifications to the OSID Assets created using the other application, while at the same time respecting the authorizations given to those assets. Additionally, an OSID Repository to OAI-PMH gateway will be shown providing the LibraryFind meta-search tool with access to the metadata for content created in Segue, Concerto, and a lightweight, read-only OSID Repository. </p>
<ul>
<li><strong>Companion Paper: </strong> <a href='http://www.adamfranco.com/wp-content/uploads/2008/06/openiworld-europe-2008-paper.pdf'>PDF (76 KB)</a></li>
<li><strong>Presentation Slides: </strong><a href='http://www.adamfranco.com/wp-content/uploads/2008/06/openiworld-europe-2008-slides.pdf'>PDF (7.4 MB)</a></li>
</ul>
<p><strong>Software Demonstrated:</strong></p>
<ul>
<li><a href="http://harmoni.sf.net">Harmoni Application Framework</a> (Middlebury College)</li>
<li><a href="http://segue.sf.net">Segue</a> version 2 (Middlebury College)</li>
<li><a href="http://concerto.sf.net">Concerto</a> (Middlebury College)</li>
<li><a href="http://www.libraryfind.org">LibraryFind</a> (Oregon State University)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/76/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Segue 2.0 &#8211; Beta 20</title>
		<link>http://www.adamfranco.com/archives/75</link>
		<comments>http://www.adamfranco.com/archives/75#comments</comments>
		<pubDate>Tue, 10 Jun 2008 03:23:52 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Segue]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=75</guid>
		<description><![CDATA[Another week, another Segue 2 beta. This week&#8217;s installation brings visitor registration, a few new themes from Alex, theme migration from Segue 1, and a bunch of little bug fixes.
Visitor registration brings with it a few interesting challenges. As in Segue 1, we want (and need) to be able to allow people outside of the [...]]]></description>
			<content:encoded><![CDATA[<p>Another week, another Segue 2 beta. This week&#8217;s installation brings visitor registration, a few new themes from Alex, theme migration from Segue 1, and a bunch of little bug fixes.</p>
<p>Visitor registration brings with it a few interesting challenges. As in Segue 1, we want (and need) to be able to allow people outside of the Middlebury community to join in on public discussions hosted in Segue. As well, Middlebury users often need to give access to restricted parts of their sites to people off-campus with whom they are collaborating. Our visitor registration system therefore needs to be easy to use by registrants, keep out spammers, as well as enable searches for visitor accounts by community users.</p>
<p>To keep out spammers, the visitor registration form uses <a href="http://recaptcha.net/">reCAPTCHA</a> to try to verify that a human is sitting at the browser. There are other CAPTCHA systems out there, but I like the philosophy and approach of reCAPTCHA. Starting with words that OCR software had trouble reading seems like a good idea. After the registration form is filled out, Segue sends an email to the address entered with a unique registration code. Until the link in the email is clicked on (and hence the address verified) the account is locked.</p>
<p>To enable easy searching of visitor accounts, visitors are asked to enter their name. While there are a few restrictions on names, these are user-chooseble. To provide some measure of differentiation between verified institution accounts and visitor accounts visitor accounts have the user-chosen name followed by their email domain name in parenthesis, e.g.: </p>
<blockquote><p>Adam Franco (gmail.com)</p></blockquote>
<p>I weighed including the entire email address as that is the only verified information we have about the visitor accounts, but I&#8217;d rather not open that information up for harvesting by spammers. If abuse becomes an issue, the visitor registration system also supports both black-lists and white-lists of email domains.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/75/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Segue 2 &#8211; The home stretch begins.</title>
		<link>http://www.adamfranco.com/archives/73</link>
		<comments>http://www.adamfranco.com/archives/73#comments</comments>
		<pubDate>Tue, 20 May 2008 04:02:24 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Segue]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/archives/73</guid>
		<description><![CDATA[We&#8217;ve recently announced our migration plans to the campus: We&#8217;ll be rolling out Segue 2 in mid-August for production use in the fall semester.
I&#8217;ve now been working on Segue 2 directly or indirectly for 5 years, since June 2003. It has been a long road and it is wonderful to finally be cresting the last [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://www.adamfranco.com/wp-content/uploads/2008/05/segue-v2-04.png' alt='Segue 2 logo' style='float: right; margin-left: 10px; margin-bottom: 10px; border: 0px;'/>We&#8217;ve recently announced our migration plans to the campus: We&#8217;ll be rolling out <a href='https://segue.middlebury.edu/sites/segue/'>Segue 2</a> in mid-August for production use in the fall semester.</p>
<p>I&#8217;ve now been working on Segue 2 directly or indirectly for 5 years, since June 2003. It has been a long road and it is wonderful to finally be cresting the last rise. That said, as the <a href="http://sourceforge.net/tracker/?group_id=82171&#038;atid=565237">feature-request tracker</a> indicates, we still have a lot to do over the next 12 weeks.</p>
<p><strong>Theming</strong><br />
This past week I rebuilt the theming system for the 4th (and last before production) time. The challenge with the theming system is that we wanted to enable end-users to choose from a few straight-forward options for things like &#8216;overall color scheme&#8217;, &#8216;font size&#8217;, corner-treatment &#8212; not all of which mapped cleanly to CSS properties. As well, to enable more powerful themes, we needed to let theme developers wrap each content type with HTML tags in order to get some effects that are just not possible with plain CSS when the dimensions of the element are not known. Our first three theming implementations involved different PHP classes for each theme with method for setting various options. Each implementation had its own strengths and weaknesses, but they were all hideously complex and required theme developers to know PHP in order to do more than change the CSS. The new theme implementation scraps all of that complexity and defines themes as a set of CSS files and HTML templates, with associated images. An extension to this simple base adds an option listing (defined in XML) that enables placeholders in the CSS and HTML templates to be replaced with values from end-user-choose-able options.</p>
<p>With the new theming system in place in development Alex has set to work building the first three (Rounded Corners, Shadow Box, and Tabs) of the themes that will be distributed with Segue while I&#8217;ve been finishing up the user-interfaces for choosing theme options and enabling more advanced users to customize the theme CSS and HTML in their web-browser. So far Alex and I are pretty happy with the new theming system and its simplicity should give it much longer legs than our previous attempts.</p>
<p>While it won&#8217;t make it to production, I eventually plan to have a theme-gallery that users can choose to publish their designs to for use by the rest of the community.</p>
<p><strong>Up Next</strong><br />
With theming out of the way the following are some of the next areas I&#8217;ll be working on in addition to fixing bugs and working out smaller kinks:</p>
<ul>
<li>Templates &#8211; starting points for sites</li>
<li>Enabling embedded videos from trusted sites (i.e. YouTube, Vimeo, etc)</li>
<li>Visitor Registration</li>
<li>Copy/Move tools for Classic Mode</li>
<li>Display of RSS feeds</li>
</ul>
<p>Still a lot to do, but with each addition Segue 2 gets much closer to being able to take over as the primary course website system.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/73/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Work updates coming to AdamFranco.com</title>
		<link>http://www.adamfranco.com/archives/72</link>
		<comments>http://www.adamfranco.com/archives/72#comments</comments>
		<pubDate>Tue, 20 May 2008 02:27:54 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/archives/72</guid>
		<description><![CDATA[I&#8217;ve been feeling the urge to record a few thoughts and ruminations related to Segue and our other development work in Curricular Technologies at Middlebury College. I already post official project news, write a lot of documentation, and keep a Twitter work-log of day to day details, but something seemed to be missing. Rather than [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been feeling the urge to record a few thoughts and ruminations related to Segue and our other development work in <a href='http://segue.middlebury.edu/sites/codelab'>Curricular Technologies at Middlebury College</a>. I already post <a href="https://segue.middlebury.edu/index.php?&#038;site=segue&#038;section=3578&#038;action=site">official project news</a>, write a lot of <a href="http://harmoni.sourceforge.net/wiki/index.php/Main_Page">documentation</a>, and keep a <a href="http://twitter.com/afranco_work">Twitter work-log</a> of day to day details, but something seemed to be missing. Rather than set up yet another blog, I figured that I would just add some work-related things here. I don&#8217;t plan on making this a work-only blog, but my personal-life postings are few and far-between enough that a little more content shouldn&#8217;t hurt.</p>
<p>If you are <em>only</em> interested in my work-related posts, check my <a href="http://www.adamfranco.com/archives/category/work">work category</a> or subscibe to <a href='http://www.adamfranco.com/archives/category/work/feed'>its feed</a>. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/archives/72/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
