Permalink
Browse files

[#778] Ant tasks start and stop

  • Loading branch information...
1 parent 8cfd80f commit abc6f4b0a15e31ef30ddcb19621fd2ac9eedb432 @erwan erwan committed Apr 27, 2011
@@ -177,6 +177,24 @@ bc. ProxyPreserveHost on
The host: header will be the original host request header issued by the client. By combining theses two techniques, your app will appear to be directly exposed.
+h2. <a name="nopython">Deploying Without Python</a>
+
+Python is installed by default on most Unix machines, and a Windows version is embedded with Play. However there may be cases where you need to deploy an application on a server without any Python executable.
+
+For that, a build.xml file providing limited functionalities is provided with Play applications.
+
+From the application folder, you can start the server using:
+
+bc. ant start -Dplay.path=/path/to/playdirectory
+
+Warning: using the play command the output will be redirected to system.out; however using ant the standard output is not accessible. It is necessary to provide a log4j properties file where you specify a file appended.
+
+To stop the server:
+
+bc. ant stop -Dplay.path=/path/to/playdirectory
+
+Note that you can also specify the path to Play framework in an environment variable or directly in your application's build.xml.
+
p(note). **Continuing the discussion**
Next: %(next)"Deployment options":deployment%.
@@ -40,9 +40,9 @@ def start(app, args):
sysout = app.readConf('application.log.system.out')
sysout = sysout!='false' and sysout!='off'
if not sysout:
- sout = None
+ sout = None
else:
- sout = open(os.path.join(app.log_path(), 'system.out'), 'w')
+ sout = open(os.path.join(app.log_path(), 'system.out'), 'w')
try:
pid = subprocess.Popen(app.java_cmd(args), stdout=sout, env=os.environ).pid
except OSError:
@@ -1,19 +1,19 @@
package play.ant;
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.types.FileSet;
-import org.apache.tools.ant.types.Path;
-import org.apache.tools.ant.types.selectors.FilenameSelector;
-import org.apache.tools.ant.util.FileUtils;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+import org.apache.tools.ant.util.FileUtils;
+
/**
* Ant task which loads settings needed by the ant from the ant configuration file.
*
@@ -0,0 +1,28 @@
+package play.ant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+import play.utils.Utils;
+
+public class StopTask extends Task {
+
+ private String pid;
+
+ public void setPid(String pid) {
+ this.pid = pid;
+ }
+
+ @Override
+ public void execute() throws BuildException {
+ if (this.pid == null) {
+ throw new BuildException("PID property missing");
+ }
+ try {
+ Utils.kill(this.pid);
+ } catch (Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+}
@@ -1,24 +1,30 @@
package play.server;
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Properties;
+import java.util.concurrent.Executors;
+
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelException;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+
import play.Logger;
import play.Play;
import play.Play.Mode;
+import play.libs.IO;
import play.server.ssl.SslHttpServerPipelineFactory;
-
-import java.io.File;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Properties;
-import java.util.concurrent.Executors;
+import play.vfs.VirtualFile;
public class Server {
public static int httpPort;
public static int httpsPort;
+ public final static String PID_FILE = "server.pid";
+
public Server(String[] args) {
System.setProperty("file.encoding", "utf-8");
@@ -120,7 +126,6 @@ public Server(String[] args) {
System.exit(-1);
}
-
}
private String getOpt(String[] args, String arg, String defaultValue) {
@@ -133,11 +138,23 @@ private String getOpt(String[] args, String arg, String defaultValue) {
return defaultValue;
}
+ private static void writePID(File root) {
+ String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
+ File pidfile = new File(root, PID_FILE);
+ if (pidfile.exists()) {
+ throw new RuntimeException("The " + PID_FILE + " already exists. Is the server already running?");
+ }
+ IO.write(pid.getBytes(), pidfile);
+ }
+
public static void main(String[] args) throws Exception {
File root = new File(System.getProperty("application.path"));
if (System.getProperty("precompiled", "false").equals("true")) {
Play.usePrecompiled = true;
}
+ if (System.getProperty("writepid", "false").equals("true")) {
+ writePID(root);
+ }
Play.init(root, System.getProperty("play.id", ""));
if (System.getProperty("precompile") == null) {
new Server(args);
@@ -1,5 +1,6 @@
package play.utils;
+import java.io.IOException;
import java.lang.annotation.Annotation;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -137,27 +138,36 @@ public static SimpleDateFormat getHttpDateFormatter() {
return newMap;
}
- public static Map<String, String> filterParams(Scope.Params params, String prefix) {
- return filterParams(params.all(), prefix);
- }
-
- public static Map<String, String> filterParams(Map<String, String[]> params, String prefix, String separator) {
- Map<String, String> filteredMap = new LinkedHashMap<String, String>();
- prefix += ".";
- for(Map.Entry<String, String[]> e: params.entrySet()){
- if(e.getKey().startsWith(prefix)) {
- filteredMap.put(
- e.getKey().substring(prefix.length()),
- Utils.join(e.getValue(), separator)
- );
- }
- }
- return filteredMap;
- }
- public static Map<String, String> filterParams(Map<String, String[]> params, String prefix) {
- return filterParams(params, prefix, ", ");
- }
-
+ public static Map<String, String> filterParams(Scope.Params params, String prefix) {
+ return filterParams(params.all(), prefix);
+ }
+
+ public static Map<String, String> filterParams(Map<String, String[]> params, String prefix, String separator) {
+ Map<String, String> filteredMap = new LinkedHashMap<String, String>();
+ prefix += ".";
+ for(Map.Entry<String, String[]> e: params.entrySet()){
+ if(e.getKey().startsWith(prefix)) {
+ filteredMap.put(
+ e.getKey().substring(prefix.length()),
+ Utils.join(e.getValue(), separator)
+ );
+ }
+ }
+ return filteredMap;
+ }
+
+ public static Map<String, String> filterParams(Map<String, String[]> params, String prefix) {
+ return filterParams(params, prefix, ", ");
+ }
+
+ public static void kill(String pid) throws Exception {
+ String os = System.getProperty("os.name");
+ String command = (os.startsWith("Windows"))
+ ? "taskkill /F /PID " + pid
+ : "kill " + pid;
+ Runtime.getRuntime().exec(command).waitFor();
+ }
+
public static class AlternativeDateFormat {
Locale locale;
@@ -203,7 +213,7 @@ public static AlternativeDateFormat getDefaultFormatter() {
"dd'/'MM'/'yyyy HH:mm:ss",
"dd-MM-yyyy HH:mm:ss",
"ddMMyyyy HHmmss",
- "ddMMyyyy"));
+ "ddMMyyyy"));
}
return dateformat.get();
}
@@ -220,28 +220,28 @@ public static VirtualFile search(Collection<VirtualFile> roots, String path) {
}
public static VirtualFile fromRelativePath(String relativePath) {
- Pattern pattern = Pattern.compile("^(\\{(.+?)\\})?(.*)$");
- Matcher matcher = pattern.matcher(relativePath);
-
- if(matcher.matches()) {
- String path = matcher.group(3);
- String module = matcher.group(2);
- if(module == null || module.equals("?") || module.equals("")) {
- return new VirtualFile(Play.applicationPath).child(path);
- } else {
- if(module.equals("play")) {
- return new VirtualFile(Play.frameworkPath).child(path);
- }
- if(module.startsWith("module:")){
- module = module.substring("module:".length());
- for(Entry<String, VirtualFile> entry : Play.modules.entrySet()) {
- if(entry.getKey().equals(module))
- return entry.getValue().child(path);
- }
- }
- }
- }
-
- return null;
+ Pattern pattern = Pattern.compile("^(\\{(.+?)\\})?(.*)$");
+ Matcher matcher = pattern.matcher(relativePath);
+
+ if(matcher.matches()) {
+ String path = matcher.group(3);
+ String module = matcher.group(2);
+ if(module == null || module.equals("?") || module.equals("")) {
+ return new VirtualFile(Play.applicationPath).child(path);
+ } else {
+ if(module.equals("play")) {
+ return new VirtualFile(Play.frameworkPath).child(path);
+ }
+ if(module.startsWith("module:")){
+ module = module.substring("module:".length());
+ for(Entry<String, VirtualFile> entry : Play.modules.entrySet()) {
+ if(entry.getKey().equals(module))
+ return entry.getValue().child(path);
+ }
+ }
+ }
+ }
+
+ return null;
}
}
@@ -2,7 +2,6 @@
<!--
General ant build file for play applications.
-Author: Heikki Uljas
Usage example:
ant -f <play path>/application-build.xml -Dplay.path=<play path> -Dbasedir=<application directory> run
@@ -29,6 +28,7 @@ And then run play just by:
<property name="application.path" value="${basedir}"/>
<property name="play.id" value=""/>
<property name="precompiled" value="false"/>
+ <property name="application.log.system.out" value="${basedir}/system.out"/>
<loadfile property="version" srcFile="${play.path}/framework/src/play/version"/>
<!-- classpath including play classes and dependencies -->
@@ -90,6 +90,12 @@ And then run play just by:
</classpath>
</taskdef>
+ <taskdef classname="play.ant.StopTask" name="playstop">
+ <classpath>
+ <pathelement location="${play.path}/framework/play-${version}.jar"/>
+ </classpath>
+ </taskdef>
+
<target name="run" description="Runs the application">
<playconfload applicationDir="${basedir}" playId="${play.id}"/>
<java classname="play.server.Server" fork="yes" failonerror="yes">
@@ -106,6 +112,32 @@ And then run play just by:
</java>
</target>
+ <target name="start" description="Starts the application as a daemon">
+ <playconfload applicationDir="${basedir}" playId="${play.id}"/>
+ <java classname="play.server.Server" fork="yes" spawn="true">
+ <classpath>
+ <path refid="play.classpath"/>
+ <path refid="modules.classpath"/>
+ <path refid="application.classpath"/>
+ </classpath>
+ <jvmarg line="-javaagent:${play.path}/framework/play-${version}.jar -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"/>
+ <sysproperty key="play.id" value="${play.id}"/>
+ <sysproperty key="play.debug" value="true"/>
+ <sysproperty key="precompiled" value="${precompiled}"/>
+ <sysproperty key="application.path" value="${basedir}"/>
+ <sysproperty key="writepid" value="true"/>
+ </java>
+ <echo message="Application started as a daemon."/>
+ <echo message="Warning: standard output is lost when running the daemon from ant. Make sure to create a log4j properties file and configure a file appender."/>
+ </target>
+
+ <target name="stop" description="Stop the application daemon">
+ <loadfile property="serverpid" srcFile="${application.path}/server.pid"/>
+ <playstop pid="${serverpid}"/>
+ <delete file="${application.path}/server.pid" />
+ <echo message="Application stopped."/>
+ </target>
+
<target name="test" description="Run the application in test mode">
<playconfload applicationDir="${basedir}" playId="test"/>
<java classname="play.server.Server" fork="yes" failonerror="yes">
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
+This file provides limited functionalities for system without Python.
+If Python is available, the play command is recommended over this build file.
+
Usage:
Example 1:
export PLAY_PATH=/home/user/play
@@ -23,6 +26,6 @@ Sets the play path to the build.xml directly.
<property environment="env"/>
<property name="play.path" value="${env.PLAY_PATH}"/>
- <import file="${play.path}/application-build.xml"/>
+ <import file="${play.path}/resources/application-build.xml"/>
</project>

1 comment on commit abc6f4b

@orefalo
Contributor

Great contribution, thank you! deploying on solaris is a pain - it's not that easy to get python 2.6 compiled. it solved my issue.

Please sign in to comment.