siark.com blog

October 8, 2010

Using mod_jk to Connect Apache 2 HTTP Server and Tomcat 6 on OS X Snow Leopard

Filed under: Systems Administration — Tags: , , , — Mark Gould @ 8:52 pm

Mac OS X Snow Leopard has the Apache HTTP Server (httpd) pre-installed (I have version 2.2.14). As I mentioned in a previous blog post, I’m using the Apache Server to handle the http requests to http://www.siark.com and I want it to forward those requests to the Tomcat servlet conainer which is listening on port 8080. To do this I’m using the Apache Tomcat Connector (mod_jk).

1 Download the Tomcat Connector version 1.2.30 source files (I downloaded the gziped tar file).

2 Decompress the downloaded file.

$ cd ~/Downloads
$ tar -xvf ~/Downloads/tomcat-connectors-1.2.30-src.tar

3 As with compiling jsvc in an earlier post, the gcc compiler in the OS X developer tools is needed. As mod_jk is an Apache Server extension module, it must be configured, compiled and then installed. To configure the make file the Apache Extension tool (apxs) is used.

$ cd tomcat-connectors-1.2.30-src/native
$ ./configure --with-apxs=/usr/sbin/apxs
$ make clean
$ make
$ sudo make install

4 To configure mod_jk two configuration files are needed, both located in /etc/apache2/other. The first file is mod_jk.conf and the second is workers.properties. For both of these files I’ve used the examples in the Quick Start HowTo on the Apache Tomcat Connector website, with some minor alterations.

$ cd /etc/apache2/other
$ sudo vi mod_jk.conf
LoadModule jk_module libexec/apache2/mod_jk.so
JkWorkersFile /etc/apache2/other/workers.properties
JkShmFile /var/log/apache2/mod_jk.shm
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
JkMount /examples/* ajp13
JkMount /host-manager/* ajp13
JkMount /docs/* ajp13
JkMount /manager/* ajp13

The JkMount directive assign URL’s to Tomcat and the JkUnmount directive blocks URL’s from being assigned to Tomcat. I have usewd a combination of these two directives to filter the appropriate URL’s to Tomcat.

$ sudo vi workers.properties
worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009

5 Finally stop and restart the Apache HTTP Server.

$ sudo apachectl graceful-stop
$ sudo apachectl start

If the server does not restart, there may be a problem with the configuration. To troubleshoot the configuration use the apachectl command with the configtest option.

Finally, visit the siark.com website.

October 1, 2010

Behaviour Driven Development With JBehave Web 3, Selenium and Maven 2 on OS X Snow Leopard

For integration testing on the siark.com webapp I’m using JBehave 3 and Selenium. As an initial test all I’m going to do is test that the home page displays the message “Welcome to the siark.com website.” when a user navigates to /igallery, the root of the siark.com website.I’m using the Page Object pattern to construct the tests.

1 Write a scenario and save it in a file called home.story in src/test/resources/com/siark/igallery/stories

Scenario: User opens home page

Given the user opens the home page
Then the home page should be displayed

2 Create a generic page class that I call IGalleryPage. The java file is created in src/test/java/com/siark/igallery.

package com.siark.igallery.pages;

import org.jbehave.web.selenium.SeleniumPage;

import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.condition.ConditionRunner;

public class IGalleryPage extends SeleniumPage {
	
	public IGalleryPage(Selenium selenium, ConditionRunner conditionRunner) {
		super(selenium, conditionRunner);
	}
}

3 Create a HomePage class that deals with the home page specifically. The java file is created in src/test/java/com/siark/igallery/pages.

package com.siark.igallery.pages;

import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.condition.ConditionRunner;

public class HomePage extends IGalleryPage {
	
	public HomePage(Selenium selenium, ConditionRunner conditionRunner) {
		super(selenium, conditionRunner);
	}
	
	public void open() {
		open("/igallery/");
	}
	
	public void verifyPage() {
		textIsVisible("Welcome to the siark.com website.");
	}
}

4 Now create a class called IGallerySteps that defines the annotations used in the story. The java file is created in src/test/java/com/siark/igallery.

package com.siark.igallery;

import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;

import com.siark.igallery.pages.FindSteps;
import com.siark.igallery.pages.HomePage;
import com.siark.igallery.pages.PageFactory;

public class IGallerySteps {
	private final PageFactory pageFactory;
	private HomePage home;
	
	public IGallerySteps(PageFactory pageFactory) {
		this.pageFactory = pageFactory;
	}
	
	@Given("the user opens the home page")
	public void theUserOpensTheHomePage() {        
		home = pageFactory.home();
		home.open();        
	}
	
	@Then("the home page should be displayed")
	public void theHomePageShouldBeDisplayed(){
		home.verifyPage();
	}
}

5 A factory class called PageFactory is used to get page classes. The java class is created in src/test/java/com/siark/igallery/pages.

package com.siark.igallery.pages;

import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.condition.ConditionRunner;

public class PageFactory {
	private final Selenium selenium;
	private final ConditionRunner conditionRunner;
	
	public PageFactory(Selenium selenium, ConditionRunner conditionRunner) {
		this.selenium = selenium;
		this.conditionRunner = conditionRunner;
	}
	
	public HomePage home() {
		return new HomePage(selenium, conditionRunner);
	}
}

6 To configure and run the tests, an embedable runnable class is created, which I have called IGalleryStories. The java file is created in src/test/java/com/siark/igallery.

package com.siark.igallery;

import static java.util.Arrays.asList;
import static org.jbehave.core.io.CodeLocations.codeLocationFromClass;
import static org.jbehave.core.reporters.StoryReporterBuilder.Format.CONSOLE;
import static org.jbehave.core.reporters.StoryReporterBuilder.Format.HTML;
import static org.jbehave.core.reporters.StoryReporterBuilder.Format.TXT;
import static org.jbehave.core.reporters.StoryReporterBuilder.Format.XML;

import java.util.List;

import org.jbehave.core.Embeddable;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.ConsoleOutput;
import org.jbehave.core.reporters.StoryReporter;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.InstanceStepsFactory;
import org.jbehave.core.steps.SilentStepMonitor;
import org.jbehave.web.selenium.SeleniumConfiguration;
import org.jbehave.web.selenium.SeleniumContext;
import org.jbehave.web.selenium.SeleniumStepMonitor;

import com.siark.igallery.pages.PageFactory;
import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.condition.ConditionRunner;

public class IGalleryStories extends JUnitStories {
	
	private Selenium selenium = SeleniumConfiguration.defaultSelenium();
	private ConditionRunner conditionRunner = SeleniumConfiguration.defaultConditionRunner(selenium);
	private PageFactory pageFactory = new PageFactory(selenium, conditionRunner);
	private SeleniumContext seleniumContext = new SeleniumContext();

	@Override
	public Configuration configuration() {
		Class<? extends Embeddable> embeddableClass = this.getClass();
		return new SeleniumConfiguration()
			.useSelenium(selenium)
			.useSeleniumContext(seleniumContext)
			.useStepMonitor(new SeleniumStepMonitor(selenium, seleniumContext, new SilentStepMonitor()))
			.useStoryLoader(new LoadFromClasspath(embeddableClass))
			.useStoryReporterBuilder(new StoryReporterBuilder() {
			
				@Override
				public StoryReporter reporterFor(String storyPath, Format format) {
					if (format == CONSOLE) {
						return new ConsoleOutput() {
							@Override
							public void beforeScenario(String title) {
								seleniumContext.setCurrentScenario(title);
								super.beforeScenario(title);
							}
						};
					} else {
						return super.reporterFor(storyPath, format);
					}
				}
			}
			.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
			.withDefaultFormats()
			.withFormats(CONSOLE, TXT, HTML, XML));
	}
	
	@Override
	public List<CandidateSteps> candidateSteps() {
		return new InstanceStepsFactory(configuration(), new IGallerySteps(pageFactory), new FailingScenarioScreenshotCapture(selenium))
		.createCandidateSteps();
	}
	
	@Override
	protected List<String> storyPaths() {
		return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()).getFile(), asList("**/*.story"), null);
	}
}

This class is actually the same class provided on the JBehave website 🙂

7 The last class is also from the JBehave website and is the FailingScenarioScreenshotCapture used in IGalleryStories. It is also created in src/test/java/com/siark/igallery.

package com.siark.igallery;

import org.jbehave.core.annotations.AfterScenario;
import org.jbehave.core.annotations.AfterScenario.Outcome;
import org.jbehave.web.selenium.PerScenarioSeleniumSteps;

import com.thoughtworks.selenium.Selenium;

public class FailingScenarioScreenshotCapture extends PerScenarioSeleniumSteps {
	public FailingScenarioScreenshotCapture(Selenium selenium) {
		super(selenium);
	}
	
	@AfterScenario(uponOutcome = Outcome.FAILURE)
	public void afterFailingScenario() throws Exception {
		String home = System.getenv("HOME");
		selenium.captureScreenshot(home+"/failedScenario.png");
	}
}

8 Finally I need to add a dependency for jbehave-web-selenium, the maven-jetty-plugin plugin so that the Jetty application server can be started and stopped and the igallery.war file can be deployed to it, the selenium-maven-plugin plugin to start and stop the Selenium server and lastly the jbehave-maven-plugin plugin to run the integration tests. The Jetty server will listen on port 8080 for HTTP requests, and the Selenium server will listen on port 4444.

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.siark.igallery</groupId>
	<artifactId>igallery</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Siark iGallery Webapp</name>
	<url>http://www.siark.com</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>org.jbehave.web</groupId>
			<artifactId>jbehave-web-selenium</artifactId>
			<version>3.0</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<finalName>igallery</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<configuration>
					<webApp>${project.build.directory}/igallery.war</webApp>
					<webAppConfig>
						<contextPath>/igallery</contextPath>
					</webAppConfig>
				</configuration>
				<executions>
					<execution>
						<id>start-jetty</id>
						<phase>pre-integration-test</phase>
						<goals>
							<goal>run-war</goal>
						</goals>
						<configuration>
							<scanIntervalSeconds>0</scanIntervalSeconds>
							<daemon>true</daemon>
						</configuration>
					</execution>
					<execution>
						<id>stop-jetty</id>
						<phase>post-integration-test</phase>
						<goals>
							<goal>stop</goal>
						</goals>
						<configuration>
							<stopKey>stopJetty</stopKey>
							<stopPort>9966</stopPort>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>selenium-maven-plugin</artifactId>
				<version>1.0.1</version>
				<executions>
					<execution>
						<id>start-selenium</id>
						<phase>pre-integration-test</phase>
						<goals>
							<goal>start-server</goal>
						</goals>
						<configuration>
							<background>true</background>
							<debug>false</debug>
							<logOutput>true</logOutput>
						</configuration>
					</execution>
					<execution>
						<id>stop-selenium</id>
						<phase>post-integration-test</phase>
						<goals>
							<goal>stop-server</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.jbehave</groupId>
				<artifactId>jbehave-maven-plugin</artifactId>
				<version>3.0</version>
				<executions>
					<execution>
						<id>run-stories</id>
						<phase>integration-test</phase>
						<configuration>
							<includes>
								<include>**/*Stories.java</include>
							</includes>
							<scope>test</scope>
						</configuration>
						<goals>
							<goal>run-stories-as-embeddables</goal>
						</goals>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>org.jbehave.web</groupId>
						<artifactId>jbehave-web-selenium</artifactId>
						<version>3.0</version>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>
	</build>
	<properties>
		<org.springframework.version>3.0.4.RELEASE</org.springframework.version>
	</properties>
</project>

September 29, 2010

Web MVC Project using Spring Framework 3 Eclipse Helios and Maven 2 on OS X Snow Leopard

I want to create the simplest of webapps using Spring Framework 3 and JSP documents. The version of JSP is 2.1 as that is the version used by Tomcat 6.

1 Update the pom.xml with the Spring Framework dependencies.

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.siark.igallery</groupId>
	<artifactId>igallery</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Siark iGallery Webapp</name>
	<url>http://www.siark.com</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>igallery</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<properties>
		<org.springframework.version>3.0.4.RELEASE</org.springframework.version>
	</properties>
</project>

2 Update the web.xml file to include the Spring Framework Dispatcher Servlet.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
	version="2.5">
	<display-name>igallery</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	<servlet>
		<servlet-name>igallery</servlet-name>
			<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>igallery</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
</web-app>

The Dispatcher Servlet handles requests to all resources that have the extension html. The DispatcherServlet class is in the spring-webmvc artifact.

3 I want the JSP pages to be in the WEB-INF/jsp directory. As this directory is not part of the public hierarchy, the welcome page (index.jsp) must redirect to the home page (home.html) which is then intercepted by the Spring Framework Dispatcher servlet.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" info="siark.com home page" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
		<title>siark.com home</title>
	</head>
	<body>
		<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
		<c:redirect url="home.html" />
	</body>
</html>

4 The Spring Framework Web MVC uses a special file to configure it’s web application context and is based on the servlet name assigned to the dispatcher servlet (igallery). This file then is igallery-servlet.xml and by default is in the WEB-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	
	<context:component-scan base-package="com.siark.igallery" />
	
	<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/jsp/"/>
		<property name="suffix" value=".jspx"/>
	</bean>
</beans>

This minimal web application context configuration file includes an entry to enable auto-detection of annotated controllers and an entry to configure the view resolver.

5 The controller for the home page is as simple as possible and just handles an HTTP GET request.

package com.siark.igallery.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@Controller
@RequestMapping("/home")
public class HomeController {
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	/**
	 *
	 */
	@RequestMapping(method=RequestMethod.GET)
	public void get() {
		logger.info("Returning the home view.");
	}
}

The Controller annotation is in the spring-context artifact and the RequestMapping and RequestMethod annotations are in the spring-web artifact.

6 The home page itself is home.jspx and is in the WEB-INF/jsp directory. It is a JSP document.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
		xmlns:c="http://java.sun.com/jsp/jstl/core"
		xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
		version="2.0">
    <jsp:directive.page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" />
    <!-- According to the W3C XHTML 1.0 Recommendation, an XML declaration is not required, but authors are strongly encouraged to use XML declarations in documents. -->
    <jsp:text>
        <![CDATA[ <?xml version="1.0" encoding="ISO-8859-1" ?> ]]>
    </jsp:text>
    <!-- According to the W3C XHTML 1.0 Recommendation, there must be a DOCTYPE declaration prior to the root element. -->
    <jsp:text>
        <![CDATA[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ]]>
    </jsp:text>
	<html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
		</head>
		<body>
			<p>Welcome to the siark.com website.</p>
		</body>
	</html>
</jsp:root>

September 20, 2010

Installing Hudson CI on OS X Snow Leopard and Configuring it to use Subversion, Maven 2 and Nexus

Filed under: Maven 2, Systems Administration — Tags: , , , , , — Mark Gould @ 2:59 pm

1 Download the hudson.war file.

2 Create a HUDSON_HOME directory. As I did with Nexus, I am creating this in the Tomcat home directory. Create the .m2 directory for maven and copy the settings.xml that configures Maven 2 to use Nexus.

$ cd /Library/Tomcat/Home
$ mkdir .hudson
$ cd .hudson
$ mkdir .m2
$ cp ~/.m2/settings.xml .
$ sudo chown tomcat settings.xml

3 Edit the Tomcat5.sh script used to start Tomcat and add a HUDSON_HOME environment variable.

$ cd bin
$ sudo vi Tomcat5.sh
...
CATALINA_OPTS="-DHUDSON_HOME=$CATALINA_HOME/.hudson/ -Xmx512m -Djava.awt.headless=true"
...

4 Stop and restart Tomcat.

$ sudo ./Tomcat5.sh stop
$ sudo ./Tomcat5.sh start

5 Deploy the hudson.war using the Tomcat Web Application Manager. To do this navigate to http://localhost:8080/manager, and half way down the page is the Deploy section with a WAR file to deploy subsection. Press the Choose File button to choose the hudson.war file. then press the Deploy button to deploy it.

6 Navigate to http://localhost:8080/hudson to check the installation worked.

7 On the Hudson home page click the ‘New Job’ link. Add the job name igallery and choose the ‘Build a maven 2 project’ radio button. Click the ‘OK’ button.

8 On the next page, choose the ‘Subversion’ radio button under the ‘Source Code Management’ section. Add ‘http://localhost/svn/repos&#8217; in the ‘Modules Repository URL’. You will need to enter the username and password setup for Subversion. Uncheck the ‘Use update’ checkbox and check the ‘Revert’ checkbox. In the ‘Build Triggers’ section check the ‘Poll SCM’ checkbox and choose a schedule. In the ‘Build’ section click the ‘system configuration’ link for the Maven Version. On the Hudson configuration page uncheck the tick box ‘Install automatically’ in the ‘Maven’ section and add ‘/usr/share/maven’ to ‘MAVEN_HOME’. Add a name for this maven installation. In the ‘Global properties’ section tick the ‘Environment variables’ checkbox and add the environment variable ‘HOME’ and give it the value ‘/Library/Tomcat/Home/.hudson’.

9 Back on the igallery job configuration page add ‘package’ to the ‘Goals and Options’ of the ‘Build’ section. Click the ‘Save’ button.

September 17, 2010

A Simple Web Application in Eclipse

A web application contains a structured hierarchy of directories. The root of the directory hierarchy is known as the document root. The WEB-INF diretory is special directory within the directory hierarchy that is not part of the public hierarchy of directories. The contents of the WEB-INF directory include the web.xml deployment descriptor file, a classes directory and a lib directory.

When a web application is packaged as a WAR file, a META-INF directory is included in the root of the directory hierarchy.

Tomcat 6 supports the Servlet 2.5 specification. The web.xml file for a web application deployed to Tomcat 6 must contain as a minimum a web-app element. However, to create the first page of the siark.com website I want to include an index.jsp page that will be used as a welcome file.

1 Create the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
	version="2.5">
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

2 Create the index.jsp file in the root of the directory hierarchy (src/main/webapp).

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" info="siark.com home page" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
		<title>siark.com home</title>
	</head>
	<body>
		<p>Welcome to the siark.com website.</p>
	</body>
</html>

To deploy and run the project, right click on the igallery project in the ‘Project Explorer’ view. Select ‘Run on Server’ from the ‘Run As’ menu item. Select the server created. Eclipse will deploy the igallery web app to the server and a browser tab will open in the Eclipse workbench displaying the landing page of the web app.

September 16, 2010

Creating a Simple Maven 2 Webapp in Eclipse

Filed under: Eclipse, Maven 2 — Tags: , , , , — Mark Gould @ 3:53 pm

1 The first component to create is the pom.xml file. An easy way to generate a simple pom.xml file is to use the Maven 2 Archetype plugin to generate a basic Maven 2 project. By default the plugin operates in interactive, so a sequence of questions must be answered to generate the project (This Maven 2 plugin could have been used to generate the original iGallery project that was committed to Subversion in the post Configuring Subversion with Apache on OS X Snow Leopard).

$ cd ~/Development
$ mvn archetype:generate
Choose archetype:
...
82: remote -> maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.)
...
Choose a number: 79:82
Choose version:
...
5: 1.0
Choose a number: 5:5
Define value for property 'groupId': :com.siark.igallery
Define value for property 'artifactId': :igallery
Define value for property 'version': 1.0-SNAPSHOT:
Define value for property 'package': com.siark.igallery:
Confirm properties configuration:
groupId: com.siark.igallery
artifactId: igallery
version: 1.0-SNAPSHOT
package: com.siark.igallery
Y:

3 Copy the contents of the pom.xml in the ~/Development/igallery directory to the empty pom.xml in the igallery Eclipse project.

4 In Eclipse, open the ‘Team Synchronising’ perspective from the ‘Window -> Open Perspective -> Other…’ dialog box.

3 Click the ‘Synchronize’ button to display the ‘Synchronize’ dialog. Select the ‘SVN’ option and press the ‘Next >’ button.

4 On the next ‘Synchronise’ dialog choose the ‘igallery’ project from the ‘Availible resources to Synchronize:’ section. Click the ‘Finish’ button. The igallery project should appear in the ‘Synchronise’ tab of this perspective.

5 The pom.xml file should be listed under the igallery project in the ‘Synchronize’ tab. Right click the pom.xml file and choose ‘Commit…’. In the dialog box that appears, enter a suitable comment to accompany the commit and press the ‘ok’ button.

6 To build the project using the m2eclipse Eclipse plugin, from the Java EE perspective right click the igallery project in the ‘Project Explorer’ and choose ‘Maven package’ from the ‘Run As’ menu item. This will generate a ‘target’ directory in the igallery directory containing amongst other things an igallery.war file. The ‘package’ Maven 2 lifecycle phase does everything except integration tests, installing the WAR file into the repository and deploying the WAR file to Tomcat.

Checking out a Project using Subclipse and Creating a new Server Runtime

Filed under: Eclipse — Tags: , , , , , — Mark Gould @ 10:20 am

Checking out the igallery project using Subclipse amd Creating a new Server Runtime.

1 Go to the SVN Repositories view. The ‘repos’ repositry set up earlier should be visible (http://siark-desktop.local/svn/repos). Click on the grey triangle to the left of the repository to expand it so that the ‘igallery’ project is visible, then expand ‘igallery’ so that ‘trunk’ is visible.

2 Right click ‘trunk’ and select ‘Checkout…’ On the first dialog box, the ‘Checkout from SVN’ dialog, leave all the options as they are and just click ‘Finish’ to checkout the project using the ‘New Project Wizard’.

3 The next dialog box is the ‘New Project’ dialog. Expand the ‘Web’ option and select the ‘Dynamic Web Project’ (a dynamic projects include resources such as Servlets and JSP files, wheras static projects just contain resources such as HTML files). Click on the ‘Next >’ button.

4 The next dialog box is the first ‘New Dynamic Web Project’ wizard dialog. Give the project a name. I’m using the name ‘igallery’. In the ‘Target Runtime’ section, press the ‘New Runtime…’ button.

5 On the ‘New Server Runtime Environment’ dialog box, select ‘Apache Tomcat v6.0’ from the expanded ‘Apache’ option. Check the ‘Create a new local server’ option so that a server is added to the ‘Servers’ view. Click the ‘Next >’ button.

6 On the next ‘New Server Runtime Environment’ dialog box, click the ‘Browse…’ button and select the Tomcat installation directory (/Library/Tomcat/Home), then click the ‘Finish’ button.

7 Back on the ‘New Dynamic Web Project’ wizard dialog, the ‘Dynamic web module version’ should be set to 2.5 (Tomcat 6 implements the Servlet 2.5 spec). Select ‘Minimal Configuration’ in the ‘Configuration’ section. Click the ‘Next >’ button.

8 On the second ‘New Dynamic Web Project’ wizard dialog, delete ‘src’ from the “Source folders on build path:’ and add ‘src/main/java’ and ‘src/test/java’ then click the ‘Next >’ button.

9 On the third and last ‘New Dynamic Web Project’ wizard dialog, change the ‘Content directory:’ to ‘src/main/webapp’. Click the ‘Finish’ button.

September 15, 2010

Maven 2 and Nexus on OS X Snow Leopard

Filed under: Maven 2 — Tags: , , , — Mark Gould @ 9:31 am

If you have the OS X Developer Tools (Xcode) installed (I have version 3.2.3), it comes with Maven 2. A quick ‘$ which mvn’ reveals mvn to be in /usr/bin. /usr/bin/mvn is a sym link to /usr/share/maven/bin/mvn and /usr/share/maven is actually a sym link to /usr/share/java/maven-2.2.0.

Download the Nexus WAR file (I downloaded nexus-webapp-1.7.2.war). Rename the WAR file nexus.war. I did consider creating a nexus user as Nexus writes information to a directory called sonatype-work, which by default is located in the home directory of the user running Tomcat, but I thought might be better located in a nexus user home directory. However, I decided just to relocate the sonatype-work directory to /Library/Tomcat/Home instead.

I deployed the nexus.war using the Tomcat Web Application Manager. To do this navigate to http://localhost:8080/manager, and half way down the page is the Deploy section with a WAR file to deploy subsection. This will deploy (and expand) the nexus.war file, but doesn’t run it. Once the WAR file is expanded, the location of the sonatype-work directory can be changed by editing the nexus-work property in the plexus.poperties file located in the WEB-INF directory of the expanded Nexus WAR.

Start Nexus by pressing the start button in the Nexus entry of the Applications section of the Tomcat Web Application Manager. If you can’t see the Applications section, press the List Applications button in the Manager section.

September 13, 2010

Installing Tomcat 6 on OS X Snow Leopard with jsvc and launchd

Filed under: Systems Administration — Tags: , , , — Mark Gould @ 4:00 pm

Although Tomcat 7 is now avalible I am using Tomcat 6 on my iMac. I’m using Tomcat version 6.0.29. I want to start Tomcat when I start my iMac. To do this I’ll start Tomcat with launchd as a daemon using jsvc.

1 Download the core Tomcat 6 binary distribution (I downloaded the gziped tar file).

2 Create a new Standard user called ‘tomcat’. This user will be used to run Tomcat (so that Tomcat is not run as root). Eventually I’ll use the Tomcat Connector aka mod_jk to connect Tomcat to Apache, so Apache will be the webserver for the siark.com website, with Tomcat as the Servlet/JSP container. Apache will, of course be using port 80 (which is why it is run as root), and Tomcat port 8080, which is why it can be run as user ‘tomcat’). Hide the tomcat user (and other) from the login screen.

$ sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add tomcat
$ sudo defaults write /Library/Preferences/com.apple.loginwindow SHOWOTHERUSERS_MANAGED -bool false

3 Create a directory for tomcat.

$ cd /Library
$ mkdir Tomcat

Create a directory for tomcat.
$ cd /Library$ mkdir Tomcat

4 Install Tomcat into the new Tomcat directory.

$ cd Tomcat
$ tar -xvzf ~/Downloads/apache-tomcat-6.0.29.tar

5 Create a symbolic link to the apache-tomcat-6.0.29 called Home.

$ ln -sfhv apache-tomcat-6.0.29 Home

6 jsvc is part of the Commons Daemon project and is included in the Tomcat download but isn’t built. As jsvc is a C program, the gcc compiler is needed to build it. The gcc compiler is included in the OS X developer tools.

$ cd /Library/Tomcat/Home/bin
$ tar -xvzf commons-daemon-native.tar.gz
$ cd commons-daemon-1.0.2-native-src/
$ cd unix

7 A quick read of the INSTALL.txt document indicates that to build an OS X Universal Binary a couple of environment variables need to be set prior to configuring make.

$ export CFLAGS="-arch i386 -arch x86_64"
$ export LDFLAGS="-arch i386 -arch x86_64"
$ ./configure
$ make clean
$ make

8 Configure the Tomcat5.sh script. Change the JAVA_HOME, CATALINA_HOME, DAEMON_HOME, TOMCAT_USER, CATALINA_BASE, CATALINA_OPTS, the ‘start’ and ‘stop’ cases

$ cd /Library/Tomcat/Home/bin/commons-daemon-1.0.2-native-src/unix/native
$ cp Tomcat5.sh ../../..
$ cd ../../..
$ vi Tomcat5.sh
JAVA_HOME=/Library/Java/Home
CATALINA_HOME=/Library/Tomcat/Home
DAEMON_HOME=$CATALINA_HOME/bin
TOMCAT_USER=mark
CATALINA_BASE=$CATALINA_HOME
CATALINA_OPTS=
start)
#
# Start Tomcat
#
$DAEMON_HOME/jsvc \
...
stop)
#
# Stop Tomcat
#
$DAEMON_HOME/jsvc \
...

9 Change the owner of the Tomcat directory to the user tomcat.

$ cd /Library
$ sudo chown -R tomcat Tomcat

10 Start Tomcat using jsvc at boot-up using launchd. Create a plist file for launchd and make root the owner of the file.

$ cd /Library/LaunchDaemons
$ sudo vi org.apache.commons.jsvc.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Disabled</key>
<false/>
<key>Label</key>
<string>org.apache.commons.jsvc</string>
<key>ProgramArguments</key>
<array>
<string>bin/Tomcat5.sh</string>
<string>start</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/Library/Tomcat/Home</string>
</dict>
</plist>
$ sudo chown root org.apache.commons.jsvc.plist

11 Test the install.

$ sudo launchctl load /Library/LaunchDaemons/org.apache.commons.jsvc.plist
$ ps -ef | grep jsvc

Resources

http://tomcat.apache.org/

http://commons.apache.org/daemon/jsvc.html

September 12, 2010

Subclipse Installation on Eclipse Helios

Filed under: Eclipse — Tags: , , , , — Mark Gould @ 6:12 pm

As I’m using Subversion for my source control and Eclipse for my editing, it made sense to install the Eclipse Subclipse plugin for Subversion. I have installed Eclipse Helios (more specifically Eclipse IDE for Java EE Developers Helios 3.6 for Mac OS X Cocoa 64 bit). It’s pretty easy to install Subclipse, I used the Eclipse Marketplace and searched for subclipse.

So far so good.

After installation and restarting Eclipse, I opened the ‘SVN repositories’ view and selected ‘New’ > ‘Repository Location…’. I duly added my repository location (http://siark-desktop.local/svn/repos) and was presented with a dialog box with the title ‘Subversion Native Library Not Available’ and containing an error saying ‘Failed to load JavaHL library’.

A little googling took me to the JavaHL Wiki and apparently the solution to my problem is to download and install the Subversion OS X package provided by CollabNet. After registering (a requirement to download) at the CollabNet website I downloaded and installed Subversion 1.6.12.

I then restarted Eclipse and retried adding my repository location and was successful 🙂

Older Posts »

Blog at WordPress.com.