Commits

Zemian Deng committed 34ace02

Added Issue#29 - make war executable.

Comments (0)

Files changed (2)

timemachine-web/pom.xml

 			<plugin>
 				<groupId>org.apache.tomcat.maven</groupId>
 				<artifactId>tomcat7-maven-plugin</artifactId>
-				<version>2.0-beta-1</version>
+				<version>2.0</version>
 			</plugin>
 			<plugin>
 				<artifactId>maven-deploy-plugin</artifactId>
 			<url>http://oss.sonatype.org/content/groups/public</url>
 		</repository>
 	</repositories>
+	
+	<profiles>
+		<profile>
+			<id>executable-war</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-war-plugin</artifactId>
+						<version>2.2</version>
+						<configuration>
+							<packagingExcludes>
+							WEB-INF/lib/winstone*.jar,
+							WEB-INF/lib/annotations-api*.jar,
+							WEB-INF/lib/ecj*.jar,
+							WEB-INF/lib/el-api*.jar,
+							WEB-INF/lib/jasper-*.jar,
+							WEB-INF/lib/juli*.jar,
+							WEB-INF/lib/jsp-api*.jar
+							</packagingExcludes>
+							<archive>
+								<manifest>
+									<mainClass>WinstoneMain</mainClass>
+								</manifest>
+							</archive>
+						</configuration>
+					</plugin>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>build-helper-maven-plugin</artifactId>
+						<version>1.1</version>
+						<executions>
+							<execution>
+								<id>add-source</id>
+								<phase>generate-sources</phase>
+								<goals>
+									<goal>add-source</goal>
+								</goals>
+								<configuration>
+									<sources>
+										<source>${basedir}/src/main/winstone</source>
+									</sources>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-dependency-plugin</artifactId>
+						<executions>
+							<execution>
+								<phase>package</phase>
+								<goals>
+									<goal>copy-dependencies</goal>
+								</goals>
+								<configuration>
+									<outputDirectory>target/${project.artifactId}-${project.version}/WEB-INF/lib-winstone</outputDirectory>
+									<includeArtifactIds>winstone,annotations-api,ecj,el-api,jasper,jasper-el,juli,jsp-api,jstl,standard</includeArtifactIds>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<artifactId>maven-antrun-plugin</artifactId>
+						<version>1.7</version>
+						<executions>
+							<execution>
+								<id>compile-main</id>
+								<phase>compile</phase>
+								<configuration>
+									<target>
+										<move todir="${basedir}/target/${project.artifactId}-${project.version}">
+											<fileset dir="${basedir}/target/classes" includes="WinstoneMain*.class" />
+										</move>
+									</target>
+								</configuration>
+								<goals>
+									<goal>run</goal>
+								</goals>
+							</execution>
+							<execution>
+								<id>package-lib-winstone</id>
+								<phase>package</phase>
+								<configuration>
+									<target>
+										<war destfile="target/${project.artifactId}-${project.version}.war" update="true">
+											<fileset dir="target/${project.artifactId}-${project.version}" includes="WEB-INF/lib-winstone/*.jar"/>
+										</war>
+									</target>
+								</configuration>
+								<goals>
+									<goal>run</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+			<dependencies>
+				<!-- Self-Contained Servlet Container lib -->
+				<dependency>
+					<groupId>net.sourceforge.winstone</groupId>
+					<artifactId>winstone</artifactId>
+					<version>0.9.10</version>
+				</dependency>
+				<!-- Jasper lib for JSP support -->
+				<dependency>
+				    <groupId>javax.servlet</groupId>
+				    <artifactId>jstl</artifactId>
+				    <version>1.1.2</version>
+				</dependency>
+				<dependency>
+					<groupId>taglibs</groupId>
+					<artifactId>standard</artifactId>
+					<version>1.1.2</version>
+				</dependency>
+				<dependency>
+					<groupId>org.apache.tomcat</groupId>
+					<artifactId>jasper</artifactId>
+					<version>6.0.35</version>
+					<scope>runtime</scope>
+					<exclusions>
+						<exclusion>
+							<groupId>org.apache.tomcat</groupId>
+							<artifactId>servlet-api</artifactId>
+						</exclusion>
+						<exclusion>
+							<artifactId>catalina</artifactId>
+							<groupId>org.apache.tomcat</groupId>
+						</exclusion>
+					</exclusions> 
+				</dependency>
+			</dependencies>
+		</profile>
+	</profiles>
 </project>

timemachine-web/src/main/winstone/WinstoneMain.java

+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.lang.reflect.*;
+
+/**
+ * A main launcher to start a tiny Winstone servlet server. We purposely not to use any package name so it can be easily loaded
+ * from inside a .war file.
+ *
+ * @author Zemian Deng <saltnlight5@gmail.com>
+ * @since 08/14/2012
+ */
+public class WinstoneMain {
+	/** Main entry */
+	public static void main(String[] args) throws Exception {
+		// Prepare a temp dir for winstone server
+		String webserverDirStr = System.getProperty("winstoneServerDir", System.getProperty("user.home") + "/.winstone");
+		File webserverDir = new File(webserverDirStr);
+		if (!webserverDir.exists())
+			webserverDir.mkdirs();
+		System.out.println("Preparing " + webserverDirStr + " directory to unpack and run web application.");
+		
+		// Extract winstone and other jars
+		URL url = WinstoneMain.class.getProtectionDomain().getCodeSource().getLocation();
+		JarFile jarFile = new JarFile(url.getFile());
+		Enumeration<JarEntry> entries = jarFile.entries();
+		while (entries.hasMoreElements()) {
+			JarEntry entry = entries.nextElement();
+			String entryName = entry.getName();
+			
+			if (entryName.startsWith("WEB-INF/lib-winstone/") && !entry.isDirectory()) {
+				String baseName = new File(entryName).getName();
+				File entryFile = new File(webserverDir, baseName);
+				if (!entryFile.exists()) {
+					System.out.println("Extracting " + entryName);
+					InputStream inStream = jarFile.getInputStream(entry);
+					FileOutputStream outStream = new FileOutputStream(entryFile);
+					while (inStream.available() > 0) {
+						outStream.write(inStream.read());
+					}
+					inStream.close();
+					outStream.close();
+				} else {
+					System.out.println("Already exists: " + entryFile);
+				}
+			}
+		}
+		
+		// Clean up webroot (temp work dir) if exists
+		File tmpDir = new File(webserverDir, "/tmp");
+		if (tmpDir.isDirectory() && tmpDir.exists()) {
+			System.out.println("Cleaning up temp directory: " + tmpDir);
+			deleteDir(tmpDir);
+		}
+		
+		// Load up the jars dynamically.
+		File winstoneJar = findWinstoneJar(webserverDir);
+		URL[] urls = new URL[]{ winstoneJar.toURL() };
+		URLClassLoader child = new URLClassLoader (urls, WinstoneMain.class.getClassLoader());
+		Class winstoneLauncher = Class.forName("winstone.Launcher", true, child);
+		Method method = winstoneLauncher.getDeclaredMethod("main", String[].class);
+		
+		// Run winstone server
+		String war = url.getFile();
+		System.out.println("Starting Winstone Servlet Container with " + war);
+		List<String> serverArgsList = new ArrayList<String>();
+		serverArgsList.add("--warfile=" + war);
+		serverArgsList.add("--ajp13Port=-1");
+		serverArgsList.add("--webroot=" + tmpDir.getAbsolutePath());
+		serverArgsList.add("--commonLibFolder=" + webserverDirStr);
+		serverArgsList.add("--useJasper");
+		serverArgsList.addAll(Arrays.asList(args));
+		System.out.println("Server args: " + serverArgsList);
+		String[] serverArgs = serverArgsList.toArray(new String[0]);
+		Object result = method.invoke(null, new Object[]{ serverArgs });
+	}
+	
+	/** Delete a dir recursively. */
+	private static void deleteDir(File dir) {
+		File[] files = dir.listFiles();
+		for (File file : files)
+			if (file.isDirectory())
+				deleteDir(file);
+			else
+				file.delete();
+		dir.delete();
+	}
+	
+	/** Find the winstone jar in a dir regardless of version value. */
+	private static File findWinstoneJar(File dir) {
+		File[] files = dir.listFiles();
+		for (File file : files)
+			if (file.getName().startsWith("winstone-"))
+				return file;
+		throw new RuntimeException("Unable to find winstone jar.");
+	}
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.