浏览代码

Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks

Michael Hixson 12 年之前
父节点
当前提交
0dd3709626
共有 100 个文件被更改,包括 2956 次插入82 次删除
  1. 6 6
      cpoll_cppsp/Makefile
  2. 31 0
      grizzly-bm/README.md
  3. 0 0
      grizzly-bm/__init__.py
  4. 12 0
      grizzly-bm/benchmark_config
  5. 85 0
      grizzly-bm/pom.xml
  6. 20 0
      grizzly-bm/setup.py
  7. 48 0
      grizzly-bm/src/main/java/org/glassfish/grizzly/bm/JsonHttpHandler.java
  8. 27 0
      grizzly-bm/src/main/java/org/glassfish/grizzly/bm/PlainTextHttpHandler.java
  9. 34 0
      grizzly-bm/src/main/java/org/glassfish/grizzly/bm/RootHttpHandler.java
  10. 48 0
      grizzly-bm/src/main/java/org/glassfish/grizzly/bm/Server.java
  11. 13 0
      installer.py
  12. 38 0
      lapis/README.md
  13. 16 0
      lapis/benchmark_config
  14. 14 0
      lapis/config.lua
  15. 10 0
      lapis/config.moon
  16. 79 0
      lapis/mime.types
  17. 43 0
      lapis/nginx.conf
  18. 16 0
      lapis/setup.py
  19. 205 0
      lapis/web.lua
  20. 57 0
      lapis/web.moon
  21. 6 1
      netty/pom.xml
  22. 1 1
      netty/setup.py
  23. 26 56
      netty/src/main/java/hello/HelloServerHandler.java
  24. 4 1
      openresty/app.lua
  25. 1 0
      openresty/benchmark_config
  26. 2 1
      php-codeigniter/application/config/database.php
  27. 7 1
      php-fuel/deploy/nginx.conf
  28. 7 1
      php-kohana/deploy/nginx.conf
  29. 7 2
      php-laravel/deploy/nginx.conf
  30. 7 1
      php-lithium/deploy/nginx.conf
  31. 7 1
      php-micromvc/deploy/nginx.conf
  32. 7 1
      php-silex-orm/deploy/nginx.conf
  33. 13 2
      php-silex/benchmark_config
  34. 7 1
      php-silex/deploy/nginx.conf
  35. 125 0
      php-silex/deploy/nginx_raw.conf
  36. 28 0
      php-silex/setup_raw.py
  37. 0 1
      php-silex/web/index.php
  38. 81 0
      php-silex/web/index_raw.php
  39. 7 1
      php-silica/deploy/nginx.conf
  40. 7 1
      php-slim/deploy/nginx.conf
  41. 7 1
      php-symfony2/deploy/nginx.conf
  42. 1 1
      php-symfony2/setup.py
  43. 7 1
      php-yaf/deploy/nginx.conf
  44. 6 0
      plain/.gitignore
  45. 0 0
      plain/__init__.py
  46. 13 0
      plain/benchmark_config
  47. 51 0
      plain/build.sbt
  48. 二进制
      plain/lib/plain-library_2.10-1.0.1-SNAPSHOT.jar
  49. 1 0
      plain/project/build.properties
  50. 20 0
      plain/project/plugins.sbt
  51. 1 0
      plain/sbt
  52. 二进制
      plain/sbt-launch.jar
  53. 24 0
      plain/setup.py
  54. 18 0
      plain/src/main/resources/application.conf
  55. 12 0
      plain/src/main/scala/com/ibm/techempower/JsonResource.scala
  56. 20 0
      plain/src/main/scala/com/ibm/techempower/PlainTextResource.scala
  57. 0 0
      treefrog/__init__.py
  58. 16 0
      treefrog/appbase.pri
  59. 13 0
      treefrog/benchmark_config
  60. 206 0
      treefrog/config/application.ini
  61. 44 0
      treefrog/config/database.ini
  62. 29 0
      treefrog/config/development.ini
  63. 51 0
      treefrog/config/initializers/internet_media_types.ini
  64. 38 0
      treefrog/config/logger.ini
  65. 27 0
      treefrog/config/mongodb.ini
  66. 10 0
      treefrog/config/routes.cfg
  67. 63 0
      treefrog/config/validation.ini
  68. 47 0
      treefrog/controllers/applicationcontroller.cpp
  69. 29 0
      treefrog/controllers/applicationcontroller.h
  70. 21 0
      treefrog/controllers/controllers.pro
  71. 110 0
      treefrog/controllers/fortunecontroller.cpp
  72. 30 0
      treefrog/controllers/fortunecontroller.h
  73. 22 0
      treefrog/controllers/jsoncontroller.cpp
  74. 23 0
      treefrog/controllers/jsoncontroller.h
  75. 131 0
      treefrog/controllers/worldcontroller.cpp
  76. 34 0
      treefrog/controllers/worldcontroller.h
  77. 1 0
      treefrog/helpers/applicationhelper.cpp
  78. 11 0
      treefrog/helpers/applicationhelper.h
  79. 13 0
      treefrog/helpers/helpers.pro
  80. 83 0
      treefrog/models/fortune.cpp
  81. 43 0
      treefrog/models/fortune.h
  82. 19 0
      treefrog/models/models.pro
  83. 31 0
      treefrog/models/sqlobjects/fortuneobject.h
  84. 31 0
      treefrog/models/sqlobjects/worldobject.h
  85. 85 0
      treefrog/models/world.cpp
  86. 43 0
      treefrog/models/world.h
  87. 28 0
      treefrog/public/403.html
  88. 28 0
      treefrog/public/404.html
  89. 28 0
      treefrog/public/413.html
  90. 29 0
      treefrog/public/500.html
  91. 36 0
      treefrog/setup.py
  92. 2 0
      treefrog/treefrog.pro
  93. 22 0
      treefrog/views/_src/_src.pro
  94. 30 0
      treefrog/views/fortune/edit.erb
  95. 27 0
      treefrog/views/fortune/entry.erb
  96. 35 0
      treefrog/views/fortune/index.erb
  97. 21 0
      treefrog/views/fortune/show.erb
  98. 1 0
      treefrog/views/mailer/.trim_mode
  99. 2 0
      treefrog/views/views.pro
  100. 30 0
      treefrog/views/world/edit.erb

+ 6 - 6
cpoll_cppsp/Makefile

@@ -1,13 +1,13 @@
 all: cppsp_0.2
 
 clean:
-	rm -rf cppsp_0.2-rc9 cppsp_0.2
+	rm -rf cppsp_rel0.2.2 cppsp_0.2
 	rm -f www/*.so www/*.txt
-cppsp_0.2: cppsp_0.2-rc9.tar.xz
-	tar xf cppsp_0.2-rc9.tar.xz
-	ln -s cppsp_0.2-rc9 cppsp_0.2
+cppsp_0.2: cppsp_0.2.2.tar.xz
+	tar xf cppsp_0.2.2.tar.xz
+	ln -s cppsp_rel0.2.2 cppsp_0.2
 	$(MAKE) CXX=g++-4.8 -C cppsp_0.2 all
 
-cppsp_0.2-rc9.tar.xz:
-	wget -c http://downloads.sourceforge.net/project/cpollcppsp/CPPSP%200.2%20%28testing%29/cppsp_0.2-rc9.tar.xz
+cppsp_0.2.2.tar.xz:
+	wget -c http://downloads.sourceforge.net/project/cpollcppsp/CPPSP%200.2%20%28testing%29/cppsp_0.2.2.tar.xz
 

+ 31 - 0
grizzly-bm/README.md

@@ -0,0 +1,31 @@
+# Grizzly Benchmarking Test
+
+This is the Grizzly portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### Plain text serialization test
+* [Plain text test resource](src/main/java/org/glassfish/grizzly/bm/PlainTextHttpHandler.java)
+
+### JSON serialization test
+* [JSON test resource](src/main/java/org/glassfish/grizzly/bm/JsonHttpHandler.java)
+
+### Database tests
+* N/A
+
+### Fortunes test
+* N/A
+
+## Versions
+
+* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
+* [Grizzly 2.3.3](http://grizzly.java.net/)
+* [Jackson 2.2.2](http://wiki.fasterxml.com/JacksonHome)
+
+## Test URLs
+
+### Plain text test
+
+    http://localhost:8080/plaintext
+
+### JSON serialization test
+
+    http://localhost:8080/json

+ 0 - 0
grizzly-bm/__init__.py


+ 12 - 0
grizzly-bm/benchmark_config

@@ -0,0 +1,12 @@
+{
+  "framework": "grizzly",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "sort": 238
+    }
+  }]
+}

+ 85 - 0
grizzly-bm/pom.xml

@@ -0,0 +1,85 @@
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.glassfish.grizzly.bm</groupId>
+    <artifactId>grizzly-bm</artifactId>
+    <version>0.1</version>
+    <packaging>jar</packaging>
+
+    <name>grizzly-bm</name>
+    <url>http://maven.apache.org</url>
+
+    <build>
+        <defaultGoal>install</defaultGoal>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+            </testResource>
+        </testResources>
+        <plugins>
+            <plugin>
+                <inherited>true</inherited>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                    <optimize>true</optimize>
+                    <debug>false</debug>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.glassfish.grizzly.bm.Server</mainClass>
+                        </manifest>
+                    </archive>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
+                        <phase>package</phase> <!-- bind to the packaging phase -->
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.grizzly</groupId>
+            <artifactId>grizzly-http-server</artifactId>
+            <version>2.3.4-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+    </dependencies>
+    <repositories>
+        <repository>
+            <id>grizzly-snapshots</id>
+            <url>https://maven.java.net/content/repositories/snapshots/</url>
+        </repository>
+    </repositories>
+</project>

+ 20 - 0
grizzly-bm/setup.py

@@ -0,0 +1,20 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  try:
+    subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="grizzly-bm")
+    subprocess.Popen("java -jar grizzly-bm-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="grizzly-bm/target")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'grizzly-bm' in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 9)
+  return 0

+ 48 - 0
grizzly-bm/src/main/java/org/glassfish/grizzly/bm/JsonHttpHandler.java

@@ -0,0 +1,48 @@
+package org.glassfish.grizzly.bm;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.util.Header;
+
+/**
+ * Json usecase
+ */
+public class JsonHttpHandler extends HttpHandler {
+
+    private final JsonFactory factory = new JsonFactory();
+
+    @Override
+    public void service(final Request request, final Response response)
+            throws Exception {
+        response.setContentType("application/json");
+        response.setHeader(Header.Server, Server.SERVER_VERSION);
+
+        JsonGenerator generator = null;
+
+        try {
+            generator = factory.createGenerator(response.getOutputStream());
+            generator.writeStartObject();
+            generator.writeStringField("message", "Hello, world");
+            generator.writeEndObject();
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } finally {
+            if (generator != null) {
+                try {
+                    generator.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    protected ExecutorService getThreadPool(Request request) {
+        return null;
+    }
+}

+ 27 - 0
grizzly-bm/src/main/java/org/glassfish/grizzly/bm/PlainTextHttpHandler.java

@@ -0,0 +1,27 @@
+package org.glassfish.grizzly.bm;
+
+import java.util.concurrent.ExecutorService;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.util.Header;
+
+/**
+ * Plain text usecase
+ */
+public class PlainTextHttpHandler extends HttpHandler {
+
+    @Override
+    public void service(final Request request, final Response response)
+            throws Exception {
+        response.setContentType("text/plain");
+        response.setCharacterEncoding("UTF-8");
+        response.setHeader(Header.Server, Server.SERVER_VERSION);
+        response.getWriter().write("Hello, World!");
+    }
+
+    @Override
+    protected ExecutorService getThreadPool(Request request) {
+        return null;
+    }
+}

+ 34 - 0
grizzly-bm/src/main/java/org/glassfish/grizzly/bm/RootHttpHandler.java

@@ -0,0 +1,34 @@
+package org.glassfish.grizzly.bm;
+
+import java.util.concurrent.ExecutorService;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.util.DataChunk;
+
+/**
+ * Root {@link HttpHandler} to be used to avoid mapping overhead
+ */
+public class RootHttpHandler extends HttpHandler {
+    private final HttpHandler plainTextHandler = new PlainTextHttpHandler();
+    private final HttpHandler jsonHandler = new JsonHttpHandler();
+    
+    @Override
+    public void service(final Request request, final Response response)
+            throws Exception {
+        // don't decode and avoid creating a string
+        final DataChunk requestURIBC = request.getRequest()
+                .getRequestURIRef().getRequestURIBC();
+        
+        if (requestURIBC.equals("/json")) {
+            jsonHandler.service(request, response);
+        } else {
+            plainTextHandler.service(request, response);
+        }
+    }
+    
+    @Override
+    protected ExecutorService getThreadPool(Request request) {
+        return null;
+    }
+}

+ 48 - 0
grizzly-bm/src/main/java/org/glassfish/grizzly/bm/Server.java

@@ -0,0 +1,48 @@
+package org.glassfish.grizzly.bm;
+
+import java.io.IOException;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+
+/**
+ * HttpServer
+ */
+public class Server {
+    public static final String SERVER_VERSION = "Grizzly/" + Grizzly.getDotedVersion();
+    
+    public static void main(String[] args) throws IOException {
+        final int port = args.length > 0
+                ? Integer.parseInt(args[0]) : 8080;
+        
+        final HttpServer httpServer = new HttpServer();
+        final NetworkListener networkListener = new NetworkListener(
+                "http-listener", "0.0.0.0", port);
+        final TCPNIOTransport transport = networkListener.getTransport();
+        
+        // force to not initialize worker thread pool
+        transport.setWorkerThreadPoolConfig(null);
+        
+        networkListener.getKeepAlive().setIdleTimeoutInSeconds(-1);
+        networkListener.getKeepAlive().setMaxRequestsCount(-1);
+        
+        httpServer.addListener(networkListener);
+        
+        httpServer.getServerConfiguration().addHttpHandler(
+                new RootHttpHandler(), "/");
+//        httpServer.getServerConfiguration().addHttpHandler(
+//                new PlainTextHttpHandler(), "/plaintext");
+//        httpServer.getServerConfiguration().addHttpHandler(
+//                new JsonHttpHandler(), "/json");
+        
+        try {
+            httpServer.start();
+            
+            System.err.print("Server started. Press ENTER to stop.\n");
+            System.in.read();
+        } finally {
+            httpServer.stop();
+        }
+    }
+}

+ 13 - 0
installer.py

@@ -300,6 +300,19 @@ class Installer:
     # siena
     self.__run_command("play-1.2.5/play1 install siena", send_yes=True)
 
+    ##############################
+    # TreeFrog Framework
+    ##############################
+    self.__run_command("sudo apt-get install qt4-qmake libqt4-dev libqt4-sql-mysql g++", True)
+    self.__run_command("wget http://downloads.sourceforge.net/project/treefrog/src/treefrog-1.6.tar.gz")
+    self.__run_command("tar xzf treefrog-1.6.tar.gz")
+    self.__run_command("rm treefrog-1.6.tar.gz")
+    self.__run_command("./configure --enable-mongo", cwd="treefrog-1.6")
+    self.__run_command("make", cwd="treefrog-1.6/src")
+    self.__run_command("sudo make install", cwd="treefrog-1.6/src")
+    self.__run_command("make", cwd="treefrog-1.6/tools")
+    self.__run_command("sudo make install", cwd="treefrog-1.6/tools")
+
     ##############################
     # Vert.x
     ##############################

+ 38 - 0
lapis/README.md

@@ -0,0 +1,38 @@
+# Lapis (Nginx + Lua(jit + Lapis)  Benchmark Test
+
+The lua app is inside [web.lua](web.lua) which is compiled using [moonscript compiler](http://moonscript.org) from [web.moon](web.moon)
+The nginx conf is inside [nginx.conf](nginx.conf)
+Requires a nginx compiled with ngx_lua module, see [openresty.org](http://openresty.org), and ngxpostgres which is bundled with openresty.
+Requires [lapis framework](http://leafo.net/lapis) installed
+    
+    luarocks install lapis
+
+Requires postgresql hostname specified as IP address, if not possible then add resolver conf to nginx.conf.
+
+The lapis benchmark is using its ORM, and no raw queries.
+
+
+## Test URLs
+### JSON Encoding 
+
+http://localhost:8080/
+
+### Single Row Random Query
+
+http://localhost:8080/db
+
+### Variable Row Query Test
+
+http://localhost:8080/db?queries=2
+
+### Fortune URL
+
+http://localhost:8080/fortunes
+
+### DB Updates URL
+
+http://localhost:8080/update?queries=2
+
+### Plaintext URL
+
+http://localhost:8080/plaintext

+ 16 - 0
lapis/benchmark_config

@@ -0,0 +1,16 @@
+{
+  "framework": "lapis",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "sort": 143
+    }
+  }]
+}

+ 14 - 0
lapis/config.lua

@@ -0,0 +1,14 @@
+local config
+do
+  local _table_0 = require("lapis.config")
+  config = _table_0.config
+end
+config("development", function()
+  return postgresql_url("postgres://benchmarkdbuser:[email protected]/hello_world")
+end)
+return config("production", function()
+  port(80)
+  num_workers(4)
+  lua_code_cache("off")
+  return postgresql_url("postgres://benchmarkdbuser:[email protected]/hello_world")
+end)

+ 10 - 0
lapis/config.moon

@@ -0,0 +1,10 @@
+import config from require "lapis.config"
+
+config "development", ->
+  postgresql_url "postgres://benchmarkdbuser:[email protected]/hello_world"
+
+config "production", ->
+  port 80
+  num_workers 4
+  lua_code_cache "off"
+  postgresql_url "postgres://benchmarkdbuser:[email protected]/hello_world"

+ 79 - 0
lapis/mime.types

@@ -0,0 +1,79 @@
+types {
+    text/html                             html htm shtml;
+    text/css                              css;
+    text/xml                              xml;
+    image/gif                             gif;
+    image/jpeg                            jpeg jpg;
+    application/x-javascript              js;
+    application/atom+xml                  atom;
+    application/rss+xml                   rss;
+
+    text/mathml                           mml;
+    text/plain                            txt;
+    text/vnd.sun.j2me.app-descriptor      jad;
+    text/vnd.wap.wml                      wml;
+    text/x-component                      htc;
+
+    image/png                             png;
+    image/tiff                            tif tiff;
+    image/vnd.wap.wbmp                    wbmp;
+    image/x-icon                          ico;
+    image/x-jng                           jng;
+    image/x-ms-bmp                        bmp;
+    image/svg+xml                         svg svgz;
+    image/webp                            webp;
+
+    application/java-archive              jar war ear;
+    application/mac-binhex40              hqx;
+    application/msword                    doc;
+    application/pdf                       pdf;
+    application/postscript                ps eps ai;
+    application/rtf                       rtf;
+    application/vnd.ms-excel              xls;
+    application/vnd.ms-powerpoint         ppt;
+    application/vnd.wap.wmlc              wmlc;
+    application/vnd.google-earth.kml+xml  kml;
+    application/vnd.google-earth.kmz      kmz;
+    application/x-7z-compressed           7z;
+    application/x-cocoa                   cco;
+    application/x-java-archive-diff       jardiff;
+    application/x-java-jnlp-file          jnlp;
+    application/x-makeself                run;
+    application/x-perl                    pl pm;
+    application/x-pilot                   prc pdb;
+    application/x-rar-compressed          rar;
+    application/x-redhat-package-manager  rpm;
+    application/x-sea                     sea;
+    application/x-shockwave-flash         swf;
+    application/x-stuffit                 sit;
+    application/x-tcl                     tcl tk;
+    application/x-x509-ca-cert            der pem crt;
+    application/x-xpinstall               xpi;
+    application/xhtml+xml                 xhtml;
+    application/zip                       zip;
+
+    application/octet-stream              bin exe dll;
+    application/octet-stream              deb;
+    application/octet-stream              dmg;
+    application/octet-stream              eot;
+    application/octet-stream              iso img;
+    application/octet-stream              msi msp msm;
+
+    audio/midi                            mid midi kar;
+    audio/mpeg                            mp3;
+    audio/ogg                             ogg;
+    audio/x-m4a                           m4a;
+    audio/x-realaudio                     ra;
+
+    video/3gpp                            3gpp 3gp;
+    video/mp4                             mp4;
+    video/mpeg                            mpeg mpg;
+    video/quicktime                       mov;
+    video/webm                            webm;
+    video/x-flv                           flv;
+    video/x-m4v                           m4v;
+    video/x-mng                           mng;
+    video/x-ms-asf                        asx asf;
+    video/x-ms-wmv                        wmv;
+    video/x-msvideo                       avi;
+}

+ 43 - 0
lapis/nginx.conf

@@ -0,0 +1,43 @@
+#worker_processes  1;
+pid        /tmp/nginx.pid;
+error_log /dev/null crit;
+#error_log /tmp/test.log error;
+env LAPIS_ENVIRONMENT;
+
+events {
+    worker_connections 16384;
+}
+
+http {
+    access_log off;
+    include mime.types;
+    lua_package_path 'CWD/lapis/?.lua;;';	
+
+    upstream database {
+        postgres_server DBHOSTNAME dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass;
+    }
+    server {
+        listen 8080;
+        lua_code_cache off;
+        charset "utf-8";
+
+        location / {
+            default_type text/html;
+            set $_url "";
+            content_by_lua_file "web.lua";
+        }
+
+        location /static/ {
+            alias static/;
+        }
+
+        location /favicon.ico {
+          alias static/favicon.ico;
+        }
+        location = /query {
+            internal;
+            postgres_pass database;
+            postgres_query $echo_request_body;
+        }
+    }
+}

+ 16 - 0
lapis/setup.py

@@ -0,0 +1,16 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  setup_util.replace_text("lapis/nginx.conf", "CWD", os.getcwd())
+  setup_util.replace_text("lapis/nginx.conf", "DBHOSTNAME", args.database_host)
+  subprocess.Popen('/usr/local/openresty/nginx/sbin/nginx -c `pwd`/nginx.conf -g "worker_processes ' + str((args.max_threads)) + ';"', shell=True, cwd="lapis")
+
+  return 0
+
+def stop():
+  subprocess.Popen('/usr/local/openresty/nginx/sbin/nginx -c `pwd`/nginx.conf -s stop', shell=True, cwd="lapis")
+
+  return 0

+ 205 - 0
lapis/web.lua

@@ -0,0 +1,205 @@
+local lapis = require("lapis")
+local db = require("lapis.db")
+local Model
+do
+  local _table_0 = require("lapis.db.model")
+  Model = _table_0.Model
+end
+local config
+do
+  local _table_0 = require("lapis.config")
+  config = _table_0.config
+end
+local insert = table.insert
+local sort = table.sort
+local random = math.random
+local Fortune
+do
+  local _parent_0 = Model
+  local _base_0 = { }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, ...)
+      if _parent_0 then
+        return _parent_0.__init(self, ...)
+      end
+    end,
+    __base = _base_0,
+    __name = "Fortune",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Fortune = _class_0
+end
+local World
+do
+  local _parent_0 = Model
+  local _base_0 = { }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, ...)
+      if _parent_0 then
+        return _parent_0.__init(self, ...)
+      end
+    end,
+    __base = _base_0,
+    __name = "World",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  World = _class_0
+end
+return lapis.serve((function()
+  local Benchmark
+  do
+    local _parent_0 = lapis.Application
+    local _base_0 = {
+      ["/"] = function(self)
+        return {
+          json = {
+            message = "Hello, World!"
+          }
+        }
+      end,
+      ["/db"] = function(self)
+        local num_queries = tonumber(self.params.queries) or 1
+        local worlds = { }
+        for i = 1, num_queries do
+          insert(worlds, World:find(random(1, 10000)))
+        end
+        return {
+          json = worlds
+        }
+      end,
+      ["/fortunes"] = function(self)
+        self.fortunes = Fortune:select("")
+        insert(self.fortunes, {
+          id = 0,
+          message = "Additional fortune added at request time."
+        })
+        sort(self.fortunes, function(a, b)
+          return a.message < b.message
+        end)
+        self.title = "Fortunes"
+        return self:html(function()
+          return element("table", function()
+            tr(function()
+              th(function()
+                return text("id")
+              end)
+              return th(function()
+                return text("message")
+              end)
+            end)
+            local _list_0 = self.fortunes
+            for _index_0 = 1, #_list_0 do
+              local fortune = _list_0[_index_0]
+              tr(function()
+                td(function()
+                  return text(fortune.id)
+                end)
+                return td(function()
+                  return text(fortune.message)
+                end)
+              end)
+            end
+          end)
+        end)
+      end,
+      ["/update"] = function(self)
+        local num_queries = tonumber(self.params.queries) or 1
+        local worlds = { }
+        for i = 1, num_queries do
+          local wid = random(1, 10000)
+          local world = World:find(wid)
+          world.randomnumber = random(1, 10000)
+          world:update("randomnumber")
+          insert(worlds, world)
+        end
+        return {
+          json = worlds
+        }
+      end,
+      ["/plaintext"] = function(self)
+        return {
+          content_type = "text/plain",
+          layout = false
+        }, "Hello, World!"
+      end
+    }
+    _base_0.__index = _base_0
+    if _parent_0 then
+      setmetatable(_base_0, _parent_0.__base)
+    end
+    local _class_0 = setmetatable({
+      __init = function(self, ...)
+        if _parent_0 then
+          return _parent_0.__init(self, ...)
+        end
+      end,
+      __base = _base_0,
+      __name = "Benchmark",
+      __parent = _parent_0
+    }, {
+      __index = function(cls, name)
+        local val = rawget(_base_0, name)
+        if val == nil and _parent_0 then
+          return _parent_0[name]
+        else
+          return val
+        end
+      end,
+      __call = function(cls, ...)
+        local _self_0 = setmetatable({}, _base_0)
+        cls.__init(_self_0, ...)
+        return _self_0
+      end
+    })
+    _base_0.__class = _class_0
+    if _parent_0 and _parent_0.__inherited then
+      _parent_0.__inherited(_parent_0, _class_0)
+    end
+    Benchmark = _class_0
+    return _class_0
+  end
+end)())

+ 57 - 0
lapis/web.moon

@@ -0,0 +1,57 @@
+lapis = require "lapis"
+db = require "lapis.db"
+import Model from require "lapis.db.model"
+import config from require "lapis.config"
+import insert from table
+import sort from table
+import random from math
+
+class Fortune extends Model
+
+class World extends Model
+
+lapis.serve class Benchmark extends lapis.Application
+  "/": =>
+    json: {message: "Hello, World!"}
+
+  "/db": =>
+    num_queries = tonumber(@params.queries) or 1
+    worlds = {}
+    for i = 1, num_queries
+      insert worlds, World\find random(1, 10000)
+    json: worlds
+
+  "/fortunes": =>
+    @fortunes = Fortune\select ""
+    insert @fortunes, {id:0, message:"Additional fortune added at request time."}
+    sort @fortunes, (a, b) -> a.message < b.message
+
+    @title = "Fortunes"
+    @html ->
+      element "table", ->
+        tr ->
+          th ->
+            text "id"
+          th ->
+            text "message"
+        for fortune in *@fortunes
+          tr ->
+            td ->
+              text fortune.id
+            td ->
+              text fortune.message
+
+  "/update": =>
+    num_queries = tonumber(@params.queries) or 1
+    worlds = {}
+    for i = 1, num_queries
+      wid = random(1, 10000)
+      world = World\find wid
+      world.randomnumber = random(1, 10000)
+      world\update "randomnumber"
+      insert worlds, world
+    json: worlds
+
+  "/plaintext": =>
+    content_type:"text/plain", layout: false, "Hello, World!"
+              

+ 6 - 1
netty/pom.xml

@@ -12,13 +12,18 @@
     <dependency>
     	<groupId>io.netty</groupId>
     	<artifactId>netty-codec-http</artifactId>
-    	<version>4.0.0.CR1</version>
+    	<version>4.0.0.CR7-SNAPSHOT</version>
     </dependency>
 	 <dependency>
 		<groupId>com.fasterxml.jackson.core</groupId>
 		<artifactId>jackson-databind</artifactId>
 		<version>2.1.1</version>
 	</dependency>
+    <dependency>
+        <groupId>org.javassist</groupId>
+        <artifactId>javassist</artifactId>
+        <version>3.18.0-GA</version>
+    </dependency>
   </dependencies>
   
   <build>

+ 1 - 1
netty/setup.py

@@ -6,7 +6,7 @@ import os
 def start(args):
   try:
     subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="netty")
-    subprocess.Popen("java -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target")
+    subprocess.Popen("java -Dio.netty.noResourceLeakDetection=true -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target")
     return 0
   except subprocess.CalledProcessError:
     return 1

+ 26 - 56
netty/src/main/java/hello/HelloServerHandler.java

@@ -1,24 +1,19 @@
 package hello;
 
-import io.netty.buffer.MessageBuf;
+import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundMessageHandlerAdapter;
-import io.netty.handler.codec.DecoderResult;
+import io.netty.channel.MessageList;
+import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.handler.codec.http.Cookie;
 import io.netty.handler.codec.http.CookieDecoder;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.DefaultHttpResponse;
 import io.netty.handler.codec.http.FullHttpResponse;
-import io.netty.handler.codec.http.HttpContent;
 import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
 import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.LastHttpContent;
 import io.netty.handler.codec.http.ServerCookieEncoder;
-import io.netty.util.CharsetUtil;
 
 import java.util.Map;
 import java.util.HashMap;
@@ -27,90 +22,66 @@ import java.util.Set;
 import java.io.*;
 
 import com.fasterxml.jackson.databind.*;
+import io.netty.util.CharsetUtil;
 
 import static io.netty.handler.codec.http.HttpHeaders.Names.*;
 import static io.netty.handler.codec.http.HttpHeaders.*;
 import static io.netty.handler.codec.http.HttpResponseStatus.*;
 import static io.netty.handler.codec.http.HttpVersion.*;
 
-public class HelloServerHandler extends ChannelInboundMessageHandlerAdapter<Object> {
+public class HelloServerHandler extends SimpleChannelInboundHandler<Object>{
 
-    private HttpRequest request;
     /** Buffer that stores the response content */
-    private final StringBuilder buf = new StringBuilder();
     private static final ObjectMapper mapper = new ObjectMapper();
 
-    private boolean flush;
+    private MessageList<Object> out;
 
     @Override
-    public boolean beginMessageReceived(ChannelHandlerContext ctx) throws Exception {
-        flush = false;
-        return super.beginMessageReceived(ctx);
+    public void beginMessageReceived(ChannelHandlerContext ctx) throws Exception {
+        out = MessageList.newInstance();
+        super.beginMessageReceived(ctx);
     }
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
-        MessageBuf<Object> out = ctx.nextOutboundMessageBuffer();
         if (msg instanceof HttpRequest) {
-            HttpRequest request = this.request = (HttpRequest) msg;
+            HttpRequest request = (HttpRequest) msg;
 
             if (is100ContinueExpected(request)) {
                 send100Continue(out);
             }
-
+            ByteBuf buf = ctx.alloc().buffer();
             if("/plaintext".equals(request.getUri())) {
-		buf.setLength(0);
-                buf.append("Hello, World!");
+                buf.writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8));
             } else {
                 Map<String, String> data = new HashMap<String, String>();
                 data.put("message", "Hello, world");
-                
-                buf.setLength(0);
+
                 try
                 {
-                  buf.append(HelloServerHandler.mapper.writeValueAsString(data));
+                  buf.writeBytes(HelloServerHandler.mapper.writeValueAsBytes(data));
                 }
                 catch (IOException ex)
                 {
                   // do nothing
                 }
             }
-
-            appendDecoderResult(buf, request);
+            writeResponse(ctx, request, buf, out);
         }
-
-        if (msg instanceof HttpContent) {
-            if (msg instanceof LastHttpContent) {
-              LastHttpContent trailer = (LastHttpContent) msg;
-              writeResponse(ctx, out, trailer);
-            }
-        }
-    }
-
-    private static void appendDecoderResult(StringBuilder buf, HttpObject o) {
-        DecoderResult result = o.getDecoderResult();
-        if (result.isSuccess()) {
-            return;
-        }
-
-        buf.append(".. WITH DECODER FAILURE: ");
-        buf.append(result.cause());
-        buf.append("\r\n");
     }
 
-    private void writeResponse(ChannelHandlerContext ctx, MessageBuf<Object> out, HttpObject currentObj) {
+    private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf, MessageList<Object> out) {
         // Decide whether to close the connection or not.
         boolean keepAlive = isKeepAlive(request);
         // Build the response object.
         FullHttpResponse response = new DefaultFullHttpResponse(
-                HTTP_1_1, currentObj.getDecoderResult().isSuccess()? OK : BAD_REQUEST,
-                Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
+                HTTP_1_1, OK, buf);
 
         response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
 
         if (keepAlive) {
             // Add 'Content-Length' header only for a keep-alive connection.
-            response.headers().set(CONTENT_LENGTH, response.data().readableBytes());
+            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
             // Add keep alive header as per:
             // - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
             response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
@@ -137,23 +108,22 @@ public class HelloServerHandler extends ChannelInboundMessageHandlerAdapter<Obje
 
         // Close the non-keep-alive connection after the write operation is done.
         if (!keepAlive) {
-            flush = false;
-            ctx.flush().addListener(ChannelFutureListener.CLOSE);
-        } else {
-            flush = true;
+            this.out = MessageList.newInstance();
+            ctx.write(out).addListener(ChannelFutureListener.CLOSE);
         }
     }
 
-    private void send100Continue(MessageBuf<Object> out) {
-        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
+    private void send100Continue(MessageList<Object> out) {
+        HttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER);
         out.add(response);
-        flush = true;
     }
 
     @Override
     public void endMessageReceived(ChannelHandlerContext ctx) throws Exception {
-        if (flush) {
-            ctx.flush();
+        if (out != null) {
+            MessageList<Object> msgs = out;
+            this.out = null;
+            ctx.write(msgs);
         }
     }
 

+ 4 - 1
openresty/app.lua

@@ -35,7 +35,10 @@ function _M.handler(ngx)
         end
         ngx.print( encode(worlds) )
         local ok, err = db:set_keepalive(0, 256)
+    elseif ngx.var.uri == '/plaintext' then
+        ngx.header.content_type = 'text/plain'
+        ngx.print('Hello, World!')
     end
 end
 
-return _M
+return _M

+ 1 - 0
openresty/benchmark_config

@@ -6,6 +6,7 @@
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/db?queries=",
+      "plaintext_url": "/plaintext",
       "port": 8080,
       "sort": 50
     }

+ 2 - 1
php-codeigniter/application/config/database.php

@@ -63,7 +63,8 @@ $db['default']['dbcollat'] = 'utf8_general_ci';
 $db['default']['swap_pre'] = '';
 $db['default']['autoinit'] = TRUE;
 $db['default']['stricton'] = FALSE;
+$db['default']['save_queries'] = FALSE;
 
 
 /* End of file database.php */
-/* Location: ./application/config/database.php */
+/* Location: ./application/config/database.php */

+ 7 - 1
php-fuel/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-kohana/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 2
php-laravel/deploy/nginx.conf

@@ -12,7 +12,6 @@ events {
     worker_connections  1024;
 }
 
-
 http {
     include       /usr/local/nginx/conf/mime.types;
     default_type  application/octet-stream;
@@ -31,6 +30,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +74,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-lithium/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-micromvc/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-silex-orm/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 13 - 2
php-silex/benchmark_config

@@ -1,12 +1,23 @@
 {
   "framework": "silex",
   "tests": [{
-    "raw": {
+    "default": {
       "setup_file": "setup",
       "db_url": "/db",
       "query_url": "/db?queries=",
       "port": 8080,
       "sort": 64
+    },
+    "raw": {
+      "setup_file": "setup_raw",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "sort": 144
     }
   }]
-}
+}

+ 7 - 1
php-silex/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 125 - 0
php-silex/deploy/nginx_raw.conf

@@ -0,0 +1,125 @@
+#user  nobody;
+worker_processes  8;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+    worker_connections  1024;
+}
+
+
+http {
+    include       /usr/local/nginx/conf/mime.types;
+    default_type  application/octet-stream;
+
+    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+    #                  '$status $body_bytes_sent "$http_referer" '
+    #                  '"$http_user_agent" "$http_x_forwarded_for"';
+
+    #access_log  logs/access.log  main;
+
+    sendfile        on;
+    #tcp_nopush     on;
+
+    #keepalive_timeout  0;
+    keepalive_timeout  65;
+
+    #gzip  on;
+
+    server {
+        listen       8080;
+        server_name  localhost;
+
+        #charset koi8-r;
+
+        #access_log  logs/host.access.log  main;
+
+        #location / {
+        #    root   html;
+        #    index  index.html index.htm;
+        #}
+
+        #error_page  404              /404.html;
+
+        # redirect server error pages to the static page /50x.html
+        #
+        #error_page   500 502 503 504  /50x.html;
+        #location = /50x.html {
+        #    root   html;
+        #}
+
+        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
+        #
+        #location ~ \.php$ {
+        #    proxy_pass   http://127.0.0.1;
+        #}
+
+        root /home/ubuntu/FrameworkBenchmarks/php-silex/web/;
+        index  index_raw.php;
+
+        location / {
+            try_files $uri $uri/ /index_raw.php?$uri&$args;
+        }
+
+        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
+        #
+        location ~ \.php$ {
+            try_files $uri =404;
+            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_index  index_raw.php;
+#            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
+            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+            include        /usr/local/nginx/conf/fastcgi_params;
+        }
+
+        # deny access to .htaccess files, if Apache's document root
+        # concurs with nginx's one
+        #
+        #location ~ /\.ht {
+        #    deny  all;
+        #}
+    }
+
+
+    # another virtual host using mix of IP-, name-, and port-based configuration
+    #
+    #server {
+    #    listen       8000;
+    #    listen       somename:8080;
+    #    server_name  somename  alias  another.alias;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+
+    # HTTPS server
+    #
+    #server {
+    #    listen       443;
+    #    server_name  localhost;
+
+    #    ssl                  on;
+    #    ssl_certificate      cert.pem;
+    #    ssl_certificate_key  cert.key;
+
+    #    ssl_session_timeout  5m;
+
+    #    ssl_protocols  SSLv2 SSLv3 TLSv1;
+    #    ssl_ciphers  HIGH:!aNULL:!MD5;
+    #    ssl_prefer_server_ciphers   on;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+}

+ 28 - 0
php-silex/setup_raw.py

@@ -0,0 +1,28 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+def start(args):
+  setup_util.replace_text("php-silex/web/index_raw.php", "192.168.100.102", "" + args.database_host + "")
+  setup_util.replace_text("php-silex/deploy/php-silex", "\".*\/FrameworkBenchmarks", "\"" + home + "/FrameworkBenchmarks")
+  setup_util.replace_text("php-silex/deploy/php-silex", "Directory .*\/FrameworkBenchmarks", "Directory " + home + "/FrameworkBenchmarks")
+  setup_util.replace_text("php-silex/deploy/nginx_raw.conf", "root .*\/FrameworkBenchmarks", "root " + home + "/FrameworkBenchmarks")
+
+  try:
+    subprocess.check_call("composer.phar install --optimize-autoloader", shell=True, cwd="php-silex")
+    subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/php-silex/deploy/php-fpm.pid", shell=True)
+    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/php-silex/deploy/nginx_raw.conf", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  try:
+    subprocess.call("sudo /usr/local/nginx/sbin/nginx -s stop", shell=True)
+    subprocess.call("sudo kill -QUIT $( cat php-silex/deploy/php-fpm.pid )", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 0 - 1
php-silex/web/index.php

@@ -40,4 +40,3 @@ $app->run();
 
 
 
-

+ 81 - 0
php-silex/web/index_raw.php

@@ -0,0 +1,81 @@
+<?php
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$app = new Silex\Application();
+
+// Test 1: JSON serialization
+$app->get('/json', function() {
+    // The following code would be handier:
+    //   return new JsonResponse(array("message" => "Hello World!"));
+    //
+    // But JsonResponse does some checks that are unneeded for this benchmark
+    // and therefore, a plain Response object is faster.
+    return new Response(json_encode(array('message' => 'Hello World!')), 200, array('Content-Type' => 'application/json'));
+});
+
+// Test 2: Single database query
+$app->get('/db', function() {
+    $db = new mysqli('192.168.100.102', 'benchmarkdbuser', 'benchmarkdbpass', 'hello_world');
+    $row = mysqli_query($db, 'SELECT id, randomNumber FROM World WHERE id = '.rand(1, 10000));
+
+    return new Response(json_encode(mysqli_fetch_assoc($row)), 200, array('Content-Type' => 'application/json'));
+});
+
+// Test 3: Multiple database queries
+$app->get('/queries', function(Request $request) {
+    $queries = max(1, min($request->query->get('queries'), 500));
+    $db = new mysqli('192.168.100.102', 'benchmarkdbuser', 'benchmarkdbpass', 'hello_world');
+
+    for ($i=0; $i<$queries; $i++) {
+        $rows[] = mysqli_fetch_assoc(mysqli_query($db, 'SELECT id, randomNumber FROM World WHERE id = '.rand(1, 10000)));
+    }
+
+    return new Response(json_encode($rows), 200, array('Content-Type' => 'application/json'));
+});
+
+// Test 4: Fortunes
+$app->get('/fortunes', function() {
+    $db = new mysqli('192.168.100.102', 'benchmarkdbuser', 'benchmarkdbpass', 'hello_world');
+    $result = mysqli_query($db, 'SELECT * FROM Fortune');
+    while ($row = mysqli_fetch_row($result)) {
+        $fortunes[$row[0]] = htmlspecialchars($row[1], ENT_IGNORE);
+    }
+    $fortunes[] = 'Additional fortune added at request time.';
+
+    asort($fortunes);
+
+    foreach ($fortunes as $i => $fortune) {
+        $templates[$i] = '<tr><td>'.$i.'</td><td>'.$fortune.'</td></tr>';
+    }
+
+    return new Response('<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'.implode('', $templates).'</table></body></html>');
+});
+
+// Test 5: Database updates
+$app->get('/updates', function(Request $request) {
+    $queries = max(1, min($request->query->get('queries'), 500));
+    $db = new mysqli('192.168.100.102', 'benchmarkdbuser', 'benchmarkdbpass', 'hello_world');
+    for ($i=0; $i<$queries; $i++) {
+        $rows[] = mysqli_fetch_assoc(mysqli_query($db, 'SELECT id, randomNumber FROM World WHERE id = '.rand(1, 10000)));
+    }
+
+    mysqli_autocommit($db, FALSE);
+    foreach ($rows as $i => $row) {
+        $rows[$i]['randomNumber'] = rand(1, 10000);
+        mysqli_query($db, "UPDATE World SET randomNumber = {$rows[$i]['randomNumber']} WHERE id = {$row['id']}");
+    }
+    mysqli_commit($db);
+
+    return new Response(json_encode($rows), 200, array('Content-Type' => 'application/json'));
+});
+
+// Test 6: Plaintext
+$app->get('/plaintext', function() {
+    return new Response('Hello World!', 200, array('Content-Type' => 'text/plain'));
+});
+
+$app->run();

+ 7 - 1
php-silica/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -73,7 +78,8 @@ http {
         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
         location ~ \.php$ {
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-slim/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 7 - 1
php-symfony2/deploy/nginx.conf

@@ -31,6 +31,11 @@ http {
 
     #gzip  on;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -70,7 +75,8 @@ http {
         #
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
 #            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 1 - 1
php-symfony2/setup.py

@@ -10,7 +10,7 @@ def start(args):
   setup_util.replace_text("php-symfony2/deploy/nginx.conf", "root .*\/FrameworkBenchmarks", "root " + home + "/FrameworkBenchmarks")
 
   try:
-    subprocess.check_call("composer.phar install", shell=True, cwd="php-symfony2")
+    subprocess.check_call("composer.phar install --optimize-autoloader", shell=True, cwd="php-symfony2")
     subprocess.check_call("php app/console cache:clear --env=prod --no-debug", shell=True, cwd="php-symfony2")
     subprocess.check_call("sudo chown -R www-data:www-data php-symfony2", shell=True)
     subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/php-symfony2/deploy/php-fpm.pid", shell=True)

+ 7 - 1
php-yaf/deploy/nginx.conf

@@ -10,6 +10,11 @@ http {
     sendfile      on;
     keepalive_timeout  65;
 
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
     server {
         listen       8080;
         server_name  localhost;
@@ -28,7 +33,8 @@ http {
 
         location ~ \.php$ {
             try_files $uri =404;
-            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
             fastcgi_index  index.php;
             include        /usr/local/nginx/conf/fastcgi_params;
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

+ 6 - 0
plain/.gitignore

@@ -0,0 +1,6 @@
+/project/.*
+/project/target
+/target
+/.project
+/.classpath
+/.cache

+ 0 - 0
plain/__init__.py


+ 13 - 0
plain/benchmark_config

@@ -0,0 +1,13 @@
+{
+    "framework" : "plain",
+    "tests" : [{
+        "default" : {
+            "setup_file" : "setup",
+            "json_url" : "/json",
+            "plaintext_url": "/plaintext",
+            "port": 8080,
+            "sort": 143
+            }
+        }
+    ]
+}

+ 51 - 0
plain/build.sbt

@@ -0,0 +1,51 @@
+import sbt._
+import spray.revolver.RevolverPlugin.Revolver
+import sbtassembly.Plugin._
+import AssemblyKeys._
+
+name := "plain-benchmark"
+
+organization := "com.ibm"
+
+scalaVersion := "2.10.2"
+
+version := "1.0"
+
+test in Compile := {}
+
+mainClass in Compile := Some("com.ibm.plain.bootstrap.Main")
+
+scalacOptions in Compile ++= Seq(
+	"-g:none",
+	"-encoding", "UTF-8", 
+	"-target:jvm-1.7", 
+	"-deprecation", 
+	"-feature", 
+	"-optimise"
+)
+
+libraryDependencies ++= Seq(
+  "org.scala-lang" % "scala-reflect" % "2.10.2",
+  "org.reflections" % "reflections" % "0.9.8",
+  "com.typesafe" % "config" % "1.0.1",
+  "ch.qos.logback" % "logback-classic" % "1.0.12",
+  "org.codehaus.janino" % "janino" % "2.6.1",
+  "com.lmax" % "disruptor" % "3.1.0",
+  "com.typesafe.akka" %% "akka-actor" % "2.1.4",
+  "com.typesafe.akka" %% "akka-slf4j" % "2.1.4",
+  "org.apache.commons" % "commons-lang3" % "3.1",
+  "org.apache.commons" % "commons-compress" % "1.4.1",
+  "commons-io" % "commons-io" % "2.4",
+  "commons-net" % "commons-net" % "3.2",
+  "commons-codec" % "commons-codec" % "1.7",
+  "com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.3.2",
+  "net.jpountz.lz4" % "lz4" % "1.1.2",
+  "com.fasterxml.jackson.core" % "jackson-databind" % "2.2.2",
+  "com.sun.jersey" % "jersey-json" % "1.17.1",
+  "org.jvnet.mimepull" % "mimepull" % "1.9.2",
+  "javax.servlet" % "servlet-api" % "2.5"
+)
+
+Revolver.settings
+
+sbtassembly.Plugin.assemblySettings

二进制
plain/lib/plain-library_2.10-1.0.1-SNAPSHOT.jar


+ 1 - 0
plain/project/build.properties

@@ -0,0 +1 @@
+sbt.version=0.12.4

+ 20 - 0
plain/project/plugins.sbt

@@ -0,0 +1,20 @@
+logLevel := Level.Warn
+
+resolvers += Resolver.url("artifactory", url("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns)
+
+resolvers += "spray repo" at "http://repo.spray.io"
+
+addSbtPlugin("com.github.retronym" % "sbt-onejar" % "0.8")
+
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.2")
+
+addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.3")
+
+addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.0.1")
+
+addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2")
+
+addSbtPlugin("io.spray" % "sbt-revolver" % "0.6.2")
+
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.8.8")
+

+ 1 - 0
plain/sbt

@@ -0,0 +1 @@
+java -Xmx3g -Xms2g -Xmn1g -Xss8M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M -Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -jar `dirname $0`/sbt-launch.jar "$@"

二进制
plain/sbt-launch.jar


+ 24 - 0
plain/setup.py

@@ -0,0 +1,24 @@
+
+import subprocess
+import sys
+import time
+import os
+
+def start(args=None):
+    subprocess.check_call("./sbt assembly", shell=True, cwd="plain")
+    subprocess.Popen("java -Xmx4g -Xss8m -jar target/scala-2.10/plain-benchmark-assembly-1.0.jar", cwd="plain", shell=True)
+    time.sleep(5)
+    return 0
+
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'plain-benchmark' in line:
+      try:
+        pid = int(line.split(None, 2)[1])
+        os.kill(pid, 9)
+      except OSError:
+        pass
+  
+  return 0

+ 18 - 0
plain/src/main/resources/application.conf

@@ -0,0 +1,18 @@
+#
+# application.conf
+#
+
+akka.event-handlers = [ "akka.event.slf4j.Slf4jEventHandler" ]
+akka.loglevel = WARNING
+
+plain.logging.level = INFO
+plain.http.startup-servers = [ benchmark-server ]
+
+benchmark-server.port-range = [ 8080 ]
+benchmark-server.dispatcher = benchmark-dispatcher
+
+benchmark-dispatcher.routes = [ 
+	{ uri = plaintext, resource-class-name = com.ibm.techempower.PlainTextResource }
+	{ uri = json, resource-class-name = com.ibm.techempower.JsonResource }
+]
+

+ 12 - 0
plain/src/main/scala/com/ibm/techempower/JsonResource.scala

@@ -0,0 +1,12 @@
+package com.ibm.techempower
+
+import com.ibm.plain.rest.Resource
+import com.ibm.plain.json.Json
+
+final class JsonResource
+
+  extends Resource {
+
+  Get { Json(Map("message" -> "Hello, World!")) }
+
+}

+ 20 - 0
plain/src/main/scala/com/ibm/techempower/PlainTextResource.scala

@@ -0,0 +1,20 @@
+package com.ibm.techempower
+
+import com.ibm.plain.rest.Resource
+import com.ibm.plain.text.`UTF-8`
+
+final class PlainTextResource
+
+  extends Resource {
+  
+  import PlainTextResource._
+
+  Get { hello }
+
+}
+
+object PlainTextResource {
+  
+  final val hello = "Hello, World!".getBytes(`UTF-8`)  
+  
+}

+ 0 - 0
treefrog/__init__.py


+ 16 - 0
treefrog/appbase.pri

@@ -0,0 +1,16 @@
+win32 {
+  INCLUDEPATH += $$quote($$(TFDIR)\\include)
+  LIBS += -L$$quote($$(TFDIR)\\bin)
+  CONFIG(debug, debug|release) {
+    LIBS += -ltreefrogd1
+  } else {
+    LIBS += -ltreefrog1
+  }
+} else {
+  macx {
+    LIBS += -framework treefrog
+  } else {
+    LIBS += -ltreefrog
+  }
+  unix:INCLUDEPATH += /usr/include/treefrog
+}

+ 13 - 0
treefrog/benchmark_config

@@ -0,0 +1,13 @@
+{
+  "framework": "treefrog",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json/json",
+      "db_url": "/world/random",
+      "query_url": "/world/queries/",
+      "port": 8800,
+      "sort": 117
+    }
+  }]
+}

+ 206 - 0
treefrog/config/application.ini

@@ -0,0 +1,206 @@
+##
+## Application settings file
+##
+[General]
+
+# Listens on the specified port.
+ListenPort=8800
+
+# Sets the codec used by 'QObject::tr()' and 'toLocal8Bit()' to the
+# QTextCodec for the specified encoding. See QTextCodec class reference.
+InternalEncoding=UTF-8
+
+# Sets the codec for http output stream to the QTextCodec for the
+# specified encoding. See QTextCodec class reference.
+HttpOutputEncoding=UTF-8
+
+# Sets the charset parameter of 'text/html' in the HTTP Content-Type
+# header to the specified string.
+HtmlContentCharset=UTF-8
+
+# Sets a language/country pair, such as en_US, ja_JP, etc.
+# If this value is empty, the system's locale is used.
+Locale=
+
+# Specify the multiprocessing module, such as 'thread' or 'prefork'
+MultiProcessingModule=thread
+
+# Specify the absolute or relative path of the temporary directory
+# for HTTP uploaded files. Uses system default if not specified.
+UploadTemporaryDirectory=tmp
+
+# Specify setting files for SQL databases.
+SqlDatabaseSettingsFiles=database.ini
+
+# Specify the setting file for MongoDB.
+MongoDbSettingsFile=
+
+# Specify the directory path to store SQL query files
+SqlQueriesStoredDirectory=sql/
+
+# Determines whether it renders views without controllers directly
+# like PHP or not, which views are stored in the directory of
+# app/views/direct. By default, this parameter is false.
+DirectViewRenderMode=false
+
+# Specify a file path for system log.
+SystemLogFile=log/treefrog.log
+
+# Specify a file path for SQL query log.
+# If it's empty or the line is commented out, output to SQL query log
+# is disabled.
+SqlQueryLogFile=log/query.log
+
+# Determines whether the application aborts (to create a core dump
+# on Unix systems) or not when it output a fatal message by tFatal()
+# method.
+ApplicationAbortOnFatal=false
+
+# This directive specifies the number of bytes from 0 (meaning
+# unlimited) to 2147483647 (2GB) that are allowed in a request body.
+LimitRequestBody=0
+
+# If false is specified, the protective function against cross-site request
+# forgery never work; otherwise it's enabled.
+EnableCsrfProtectionModule=false
+
+##
+## Session section
+##
+Session.Name=TFSESSION
+
+# Specify the session store type, such as 'sqlobject', 'file', 'cookie'
+# or plugin module name.
+Session.StoreType=cookie
+
+# Replaces the session ID with a new one each time one connects, and
+# keeps the current session information.
+Session.AutoIdRegeneration=false
+
+# Specifies the lifetime of the session in seconds. The value 0 means
+# "until the browser is closed." Defaults to 0.
+Session.LifeTime=0
+
+# Specifies path to set in the session cookie. Defaults to /.
+Session.CookiePath=/
+
+# Probability that the garbage collection starts.
+# If 100 specified, the GC of sessions starts at the rate of once per 100
+# accesses. If 0 specified, the GC never starts.
+Session.GcProbability=100
+
+# Specifies the number of seconds after which session data will be seen as
+# 'garbage' and potentially cleaned up.
+Session.GcMaxLifeTime=1800
+
+# Secret key for verifying cookie session data integrity.
+# Enter at least 30 characters and all random.
+Session.Secret=0I3EINu8nxl1hMu0dVDdDpIvbT2zKs
+
+# Specify CSRF protection key.
+# Uses it in case of cookie session.
+Session.CsrfProtectionKey=_csrfId
+
+##
+## MPM Thread section
+##
+
+# Maximum number of server threads allowed to start
+MPM.thread.MaxServers=512
+
+##
+## MPM Prefork section
+##
+
+# Maximum number of server processes allowed to start
+MPM.prefork.MaxServers=20
+
+# Minimum number of server processes allowed to start
+MPM.prefork.MinServers=5
+
+# Number of server processes which are kept spare
+MPM.prefork.SpareServers=5
+
+##
+## SystemLog settings
+##
+
+# Specify the system log file name.
+SystemLog.FilePath=log/treefrog.log
+
+# Specify the layout of the system log
+#  %d : Date-time
+#  %p : Priority (lowercase)
+#  %P : Priority (uppercase)
+#  %t : Thread ID (dec)
+#  %T : Thread ID (hex)
+#  %i : PID (dec)
+#  %I : PID (hex)
+#  %m : Log message
+#  %n : Newline code
+SystemLog.Layout="%d %5P [%t] %m%n"
+
+# Specify the date-time format of the system log
+SystemLog.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+##
+## AccessLog settings
+##
+
+# Specify the access log file name.
+AccessLog.FilePath=log/access.log
+
+# Specify the layout of the access log.
+#  %h : Remote host
+#  %d : Date-time the request was received
+#  %r : First line of request
+#  %s : Status code
+#  %O : Bytes sent, including headers, cannot be zero
+#  %n : Newline code
+AccessLog.Layout="%h %d \"%r\" %s %O%n"
+
+# Specify the date-time format of the access log
+AccessLog.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+##
+## ActionMailer section
+##
+
+# Specify the delivery method such as "smtp" or "sendmail".
+# If empty, the mail is not sent.
+ActionMailer.DeliveryMethod=smtp
+
+# Specify the character set of email. The system encodes with this codec,
+# and sends the encoded mail.
+ActionMailer.CharacterSet=UTF-8
+
+##
+## ActionMailer SMTP section
+##
+
+# Specify the connection's host name or IP address.
+ActionMailer.smtp.HostName=
+
+# Specify the connection's port number.
+ActionMailer.smtp.Port=
+
+# Enables SMTP authentication if true; disables SMTP
+# authentication if false.
+ActionMailer.smtp.Authentication=false
+
+# Specify the user name for SMTP authentication.
+ActionMailer.smtp.UserName=
+
+# Specify the password for SMTP authentication.
+ActionMailer.smtp.Password=
+
+# Enables the delayed delivery of email if true. If enabled, deliver() method
+# only adds the email to the queue and therefore the method doesn't block.
+ActionMailer.smtp.DelayedDelivery=false
+
+##
+## ActionMailer Sendmail section
+## 
+
+#ActionMailer.sendMail.CommandLocation=/usr/sbin/sendmail
+

+ 44 - 0
treefrog/config/database.ini

@@ -0,0 +1,44 @@
+#
+# Database settings file
+#
+
+# The currently available driver types are:  
+#  [Driver Type] [Description]
+#   QDB2          IBM DB2
+#   QIBASE        Borland InterBase Driver
+#   QMYSQL        MySQL Driver
+#   QOCI          Oracle Call Interface Driver
+#   QODBC         ODBC Driver (includes Microsoft SQL Server)
+#   QPSQL         PostgreSQL Driver
+#   QSQLITE       SQLite version 3 or above
+#   QSQLITE2      SQLite version 2
+#
+# In case of SQLite, specify the DB file path to DatabaseName as follows;
+# DatabaseName=db/dbfile
+
+[dev]
+DriverType=QMYSQL
+DatabaseName=hello_world
+HostName=localhost
+Port=
+UserName=root
+Password=secret
+ConnectOptions=
+
+[test]
+DriverType=QMYSQL
+DatabaseName=
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[product]
+DriverType=QMYSQL
+DatabaseName=hello_world
+HostName=localhost
+Port=
+UserName=root
+Password=secret
+ConnectOptions=

+ 29 - 0
treefrog/config/development.ini

@@ -0,0 +1,29 @@
+##
+## Development settings file
+##
+[General]
+
+##
+## Template system section
+##
+
+# Specify the template system of view, ERB or Otama.
+TemplateSystem=ERB
+
+
+##
+## ERB section
+## 
+
+# Specify the trim mode of ERB.
+#  0 : off
+#  1 : normal trim mode
+#  2 : strong trim mode
+Erb.DefaultTrimMode=1
+
+
+##
+## Otama section
+##
+Otama.ReplaceMarker=%%
+

+ 51 - 0
treefrog/config/initializers/internet_media_types.ini

@@ -0,0 +1,51 @@
+# 
+# Internet media type settings file
+#
+# (extension)=(internet media type)
+
+[General]
+# application
+pdf=application/pdf
+js=application/javascript
+zip=application/zip
+ogg=application/ogg
+ogx=application/ogg
+doc=application/msword
+xls=application/vnd.ms-excel
+ppt=application/vnd.ms-powerpoint
+
+# audio
+oga=audio/ogg
+mp3=audio/mpeg
+m4a=audio/mp4
+
+# image
+jpeg=image/jpeg
+jpg=image/jpeg
+gif=image/gif
+png=image/png
+tif=image/tiff
+tiff=image/tiff
+ico=image/vnd.microsoft.icon
+
+# text
+txt=text/plain
+html=text/html
+htm=text/html
+shtml=text/html
+xml=text/xml
+rss=text/xml
+rtf=text/rtf
+css=text/css
+csv=text/csv
+
+# video
+ogv=video/ogg
+3gp=video/3gpp
+3gpp=video/3gpp
+mp4=video/mp4
+mov=video/quicktime
+webm=video/webm
+flv=video/x-flv
+wmv=video/x-ms-wmv
+avi=video/x-msvideo

+ 38 - 0
treefrog/config/logger.ini

@@ -0,0 +1,38 @@
+##
+## Logger settings file
+##
+[General]
+
+# Specify loggers
+Loggers=FileLogger
+
+# Specify the default log text encoding. If not specified,
+# the codec will be based on a system locale.
+DefaultTextEncoding=
+
+##
+## FileLogger section
+##
+
+# Specify the application log file name.
+FileLogger.Target=log/app.log
+
+# Specify the layout of FileLogger.
+#  %d : date-time
+#  %p : priority (lowercase)
+#  %P : priority (uppercase)
+#  %t : thread ID (dec)
+#  %T : thread ID (hex)
+#  %i : PID (dec)
+#  %I : PID (hex)
+#  %m : log message
+#  %n : newline code
+FileLogger.Layout="%d %5P [%t] %m%n"
+
+# Specify the date-time format of FileLogger, see also QDateTime
+# class reference.
+FileLogger.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+# Outputs the logs of equal or higher priority than this.
+FileLogger.Threshold=debug
+

+ 27 - 0
treefrog/config/mongodb.ini

@@ -0,0 +1,27 @@
+#
+# MongoDB settings file
+#
+
+[dev]
+DatabaseName=mdb
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[test]
+DatabaseName=
+HostName=
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[product]
+DatabaseName=
+HostName=
+Port=
+UserName=
+Password=
+ConnectOptions=

+ 10 - 0
treefrog/config/routes.cfg

@@ -0,0 +1,10 @@
+# routes.cfg
+
+# The priority is based upon order of creation:
+# first created -> highest priority.
+
+# Samples of regular routes:
+#   match  "/Book"  "Book#view"
+#   get    "/"  "Blog#index"
+#   post   "/New/:params"  "Account#entry"
+

+ 63 - 0
treefrog/config/validation.ini

@@ -0,0 +1,63 @@
+#
+# Validation settings file.
+#
+[General]
+
+# Sets the date format.
+# If you use the expression of short or long month name, note that the
+# application's locale settings. See QDate class reference.
+DateFormat="yyyy-MM-dd"
+
+# Sets the time format.
+# See QTime class reference.
+TimeFormat="hh:mm:ss"
+
+# Sets the date-time format.
+# If you use the expression of short or long month name, note that the
+# application's locale settings. See QDateTime class reference.
+DateTimeFormat="yyyy-MM-ddThh:mm:ss"
+
+#
+# Sets the default error messages below.
+#
+[ErrorMessage]
+
+# Required error
+0=This value is required.
+
+# MaxLength error
+1=This value is too long.
+
+# MinLength error
+2=This value is too short.
+
+# IntMax error
+3=This value is too big.
+
+# IntMin error
+4=This value is too small.
+
+# DoubleMax error
+5=This value is too big.
+
+# DoubleMin error
+6=This value is too small.
+
+# EMailAddress error
+7=This value is not email address.
+
+# Url error
+8=This value is invalid URL.
+
+# Date error
+9=This value is invalid date.
+
+# Time error
+10=This value is invalid time.
+
+# DateTime Error
+11=This value is invalid date or time.
+
+# UserDefined error
+12=This value is bad format.
+

+ 47 - 0
treefrog/controllers/applicationcontroller.cpp

@@ -0,0 +1,47 @@
+#include "applicationcontroller.h"
+
+
+ApplicationController::ApplicationController()
+    : TActionController()
+{ }
+
+ApplicationController::ApplicationController(const ApplicationController &)
+    : TActionController()
+{ }
+
+ApplicationController::~ApplicationController()
+{ }
+
+void ApplicationController::staticInitialize()
+{ }
+
+bool ApplicationController::preFilter()
+{
+    return true;
+}
+
+QString ApplicationController::jsonEncode(const QVariantMap &obj)
+{
+    QString ret("{");
+    for (QMap<QString, QVariant>::const_iterator i = obj.begin(); i != obj.end(); ++i) {
+        ret += QString("\"%1\": \"%2\", ").arg(i.key()).arg(i.value().toString());
+    }
+    ret.chop(2);
+    ret += QLatin1Char('}');
+    return ret;
+}
+
+QString ApplicationController::jsonEncode(const QList<QVariantMap> &lst)
+{
+    QString ret("[");
+    for (QListIterator<QVariantMap> it(lst); it.hasNext(); ) {
+      ret += jsonEncode(it.next());
+      ret += QLatin1String(", ");
+    }
+    ret.chop(2);
+    ret += QLatin1Char(']');
+    return ret;
+}
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(applicationcontroller)

+ 29 - 0
treefrog/controllers/applicationcontroller.h

@@ -0,0 +1,29 @@
+#ifndef APPLICATIONCONTROLLER_H
+#define APPLICATIONCONTROLLER_H
+
+#include <TActionController>
+#include <QVariantMap>
+#include <QList>
+#include "applicationhelper.h"
+
+
+class T_CONTROLLER_EXPORT ApplicationController : public TActionController
+{
+    Q_OBJECT
+public:
+    ApplicationController();
+    ApplicationController(const ApplicationController &other);
+    virtual ~ApplicationController();
+    static QString jsonEncode(const QVariantMap &obj);
+    static QString jsonEncode(const QList<QVariantMap> &list);
+
+public slots:
+    void staticInitialize();
+
+protected:
+    virtual bool preFilter();    
+};
+
+T_DECLARE_CONTROLLER(ApplicationController, applicationcontroller)
+
+#endif // APPLICATIONCONTROLLER_H

+ 21 - 0
treefrog/controllers/controllers.pro

@@ -0,0 +1,21 @@
+TARGET = controller
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += network sql xml
+QT -= gui
+DEFINES += TF_DLL
+DESTDIR = ../lib
+INCLUDEPATH += ../helpers ../models
+DEPENDPATH  += ../helpers ../models
+LIBS += -L../lib -lhelper -lmodel
+
+include(../appbase.pri)
+
+HEADERS += applicationcontroller.h
+SOURCES += applicationcontroller.cpp
+HEADERS += fortunecontroller.h
+SOURCES += fortunecontroller.cpp
+HEADERS += worldcontroller.h
+SOURCES += worldcontroller.cpp
+HEADERS += jsoncontroller.h
+SOURCES += jsoncontroller.cpp

+ 110 - 0
treefrog/controllers/fortunecontroller.cpp

@@ -0,0 +1,110 @@
+#include "fortunecontroller.h"
+#include "fortune.h"
+
+
+FortuneController::FortuneController(const FortuneController &)
+    : ApplicationController()
+{ }
+
+void FortuneController::index()
+{
+    QList<Fortune> fortuneList = Fortune::getAll();
+    texport(fortuneList);
+    render();
+}
+
+void FortuneController::show(const QString &pk)
+{
+    Fortune fortune = Fortune::get(pk.toUInt());
+    texport(fortune);
+    render();
+}
+
+void FortuneController::entry()
+{
+    renderEntry();
+}
+
+void FortuneController::create()
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("fortune");
+    Fortune fortune = Fortune::create(form);
+    if (!fortune.isNull()) {
+        QString notice = "Created successfully.";
+        tflash(notice);
+        redirect(urla("show", fortune.id()));
+    } else {
+        QString error = "Failed to create.";
+        texport(error);
+        renderEntry(form);
+    }
+}
+
+void FortuneController::renderEntry(const QVariantMap &fortune)
+{
+    texport(fortune);
+    render("entry");
+}
+
+void FortuneController::edit(const QString &pk)
+{
+    Fortune fortune = Fortune::get(pk.toUInt());
+    if (!fortune.isNull()) {
+        renderEdit(fortune.toVariantMap());
+    } else {
+        redirect(urla("entry"));
+    }
+}
+
+void FortuneController::save(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QString error;
+    Fortune fortune = Fortune::get(pk.toUInt());
+    if (fortune.isNull()) {
+        error = "Original data not found. It may have been updated/removed by another transaction.";
+        tflash(error);
+        redirect(urla("edit", pk));
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("fortune");
+    fortune.setProperties(form);
+    if (fortune.save()) {
+        QString notice = "Updated successfully.";
+        tflash(notice);
+        redirect(urla("show", pk));
+    } else {
+        error = "Failed to update.";
+        texport(error);
+        renderEdit(form);
+    }
+}
+
+void FortuneController::renderEdit(const QVariantMap &fortune)
+{
+    texport(fortune);
+    render("edit");
+}
+
+void FortuneController::remove(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    Fortune fortune = Fortune::get(pk.toUInt());
+    fortune.remove();
+    redirect(urla("index"));
+}
+
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(fortunecontroller)

+ 30 - 0
treefrog/controllers/fortunecontroller.h

@@ -0,0 +1,30 @@
+#ifndef FORTUNECONTROLLER_H
+#define FORTUNECONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT FortuneController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    FortuneController() { }
+    FortuneController(const FortuneController &other);
+
+public slots:
+    void index();
+    void show(const QString &pk);
+    void entry();
+    void create();
+    void edit(const QString &pk);
+    void save(const QString &pk);
+    void remove(const QString &pk);
+
+private:
+    void renderEntry(const QVariantMap &fortune = QVariantMap());
+    void renderEdit(const QVariantMap &fortune = QVariantMap());
+};
+
+T_DECLARE_CONTROLLER(FortuneController, fortunecontroller)
+
+#endif // FORTUNECONTROLLER_H

+ 22 - 0
treefrog/controllers/jsoncontroller.cpp

@@ -0,0 +1,22 @@
+#include "jsoncontroller.h"
+
+JsonController::JsonController(const JsonController &)
+    : ApplicationController()
+{ }
+
+void JsonController::index()
+{
+    // write codes
+}
+
+void JsonController::json()
+{
+    QVariantMap obj;
+    obj["message"] = "Hello, World!";
+
+    setContentType("application/json");
+    renderText(jsonEncode(obj), false);
+}
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(jsoncontroller)

+ 23 - 0
treefrog/controllers/jsoncontroller.h

@@ -0,0 +1,23 @@
+#ifndef JSONCONTROLLER_H
+#define JSONCONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT JsonController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    JsonController() { }
+    JsonController(const JsonController &other);
+    bool sessionEnabled() const { return false; }
+    bool transactionEnabled() const { return false; }
+
+public slots:
+    void index();
+    void json();
+};
+
+T_DECLARE_CONTROLLER(JsonController, jsoncontroller)
+
+#endif // JSONCONTROLLER_H

+ 131 - 0
treefrog/controllers/worldcontroller.cpp

@@ -0,0 +1,131 @@
+#include "worldcontroller.h"
+#include "world.h"
+
+
+WorldController::WorldController(const WorldController &)
+    : ApplicationController()
+{ }
+
+void WorldController::index()
+{
+    QList<World> worldList = World::getAll();
+    texport(worldList);
+    render();
+}
+
+void WorldController::show(const QString &pk)
+{
+    World world = World::get(pk.toUInt());
+    texport(world);
+    render();
+}
+
+void WorldController::queries(const QString &num)
+{
+    QList<QVariantMap> worlds;
+    int d = num.toInt();
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(9999) + 1;
+	World world = World::get(id);
+	worlds << world.toVariantMap();
+    }
+    setContentType("application/json");
+    renderText(jsonEncode(worlds), false);
+}
+
+void WorldController::random()
+{
+    int id = Tf::random(9999) + 1;
+    World world = World::get(id);
+    setContentType("application/json");
+    renderText(jsonEncode(world.toVariantMap()), false);
+}
+
+void WorldController::entry()
+{
+    renderEntry();
+}
+
+void WorldController::create()
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("world");
+    World world = World::create(form);
+    if (!world.isNull()) {
+        QString notice = "Created successfully.";
+        tflash(notice);
+        redirect(urla("show", world.id()));
+    } else {
+        QString error = "Failed to create.";
+        texport(error);
+        renderEntry(form);
+    }
+}
+
+void WorldController::renderEntry(const QVariantMap &world)
+{
+    texport(world);
+    render("entry");
+}
+
+void WorldController::edit(const QString &pk)
+{
+    World world = World::get(pk.toUInt());
+    if (!world.isNull()) {
+        renderEdit(world.toVariantMap());
+    } else {
+        redirect(urla("entry"));
+    }
+}
+
+void WorldController::save(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QString error;
+    World world = World::get(pk.toUInt());
+    if (world.isNull()) {
+        error = "Original data not found. It may have been updated/removed by another transaction.";
+        tflash(error);
+        redirect(urla("edit", pk));
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("world");
+    world.setProperties(form);
+    if (world.save()) {
+        QString notice = "Updated successfully.";
+        tflash(notice);
+        redirect(urla("show", pk));
+    } else {
+        error = "Failed to update.";
+        texport(error);
+        renderEdit(form);
+    }
+}
+
+void WorldController::renderEdit(const QVariantMap &world)
+{
+    texport(world);
+    render("edit");
+}
+
+void WorldController::remove(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    World world = World::get(pk.toUInt());
+    world.remove();
+    redirect(urla("index"));
+}
+
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(worldcontroller)

+ 34 - 0
treefrog/controllers/worldcontroller.h

@@ -0,0 +1,34 @@
+#ifndef WORLDCONTROLLER_H
+#define WORLDCONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT WorldController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    WorldController() { }
+    WorldController(const WorldController &other);
+    bool sessionEnabled() const { return false; }
+    bool transactionEnabled() const { return false; }
+
+public slots:
+    void index();
+    void show(const QString &pk);
+    void queries(const QString &num);
+    void random();
+    void entry();
+    void create();
+    void edit(const QString &pk);
+    void save(const QString &pk);
+    void remove(const QString &pk);
+
+private:
+    void renderEntry(const QVariantMap &world = QVariantMap());
+    void renderEdit(const QVariantMap &world = QVariantMap());
+};
+
+T_DECLARE_CONTROLLER(WorldController, worldcontroller)
+
+#endif // WORLDCONTROLLER_H

+ 1 - 0
treefrog/helpers/applicationhelper.cpp

@@ -0,0 +1 @@
+#include "applicationhelper.h"

+ 11 - 0
treefrog/helpers/applicationhelper.h

@@ -0,0 +1,11 @@
+#ifndef APPLICATIONHELPER_H
+#define APPLICATIONHELPER_H
+
+#include <TGlobal>
+
+
+class T_HELPER_EXPORT ApplicationHelper
+{
+};
+
+#endif // APPLICATIONHELPER_H

+ 13 - 0
treefrog/helpers/helpers.pro

@@ -0,0 +1,13 @@
+TARGET = helper
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT  -= gui
+QT  += 
+DEFINES += TF_DLL
+DESTDIR = ../lib
+DEPENDPATH +=
+
+include(../appbase.pri)
+
+HEADERS += applicationhelper.h
+SOURCES += applicationhelper.cpp

+ 83 - 0
treefrog/models/fortune.cpp

@@ -0,0 +1,83 @@
+#include <TreeFrogModel>
+#include "fortune.h"
+#include "fortuneobject.h"
+
+Fortune::Fortune()
+    : TAbstractModel(), d(new FortuneObject)
+{ }
+
+Fortune::Fortune(const Fortune &other)
+    : TAbstractModel(), d(new FortuneObject(*other.d))
+{ }
+
+Fortune::Fortune(const FortuneObject &object)
+    : TAbstractModel(), d(new FortuneObject(object))
+{ }
+
+Fortune::~Fortune()
+{
+    // If the reference count becomes 0,
+    // the shared data object 'FortuneObject' is deleted.
+}
+
+uint Fortune::id() const
+{
+    return d->id;
+}
+
+QString Fortune::message() const
+{
+    return d->message;
+}
+
+void Fortune::setMessage(const QString &message)
+{
+    d->message = message;
+}
+
+Fortune &Fortune::operator=(const Fortune &other)
+{
+    d = other.d;  // increments the reference count of the data
+    return *this;
+}
+
+Fortune Fortune::create(const QString &message)
+{
+    FortuneObject obj;
+    obj.message = message;
+    if (!obj.create()) {
+        obj.clear();
+    }
+    return Fortune(obj);
+}
+
+Fortune Fortune::create(const QVariantMap &values)
+{
+    Fortune model;
+    model.setProperties(values);
+    if (!model.d->create()) {
+        model.d->clear();
+    }
+    return model;
+}
+
+Fortune Fortune::get(const uint &id)
+{
+    TSqlORMapper<FortuneObject> mapper;
+    return Fortune(mapper.findByPrimaryKey(id));
+}
+
+QList<Fortune> Fortune::getAll()
+{
+    return tfGetModelListByCriteria<Fortune, FortuneObject>(TCriteria());
+}
+
+TSqlObject *Fortune::data()
+{
+    return d.data();
+}
+
+const TSqlObject *Fortune::data() const
+{
+    return d.data();
+}

+ 43 - 0
treefrog/models/fortune.h

@@ -0,0 +1,43 @@
+#ifndef FORTUNE_H
+#define FORTUNE_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QVariant>
+#include <QSharedDataPointer>
+#include <TGlobal>
+#include <TAbstractModel>
+
+class TSqlObject;
+class FortuneObject;
+
+
+class T_MODEL_EXPORT Fortune : public TAbstractModel
+{
+public:
+    Fortune();
+    Fortune(const Fortune &other);
+    Fortune(const FortuneObject &object);
+    ~Fortune();
+
+    uint id() const;
+    QString message() const;
+    void setMessage(const QString &message);
+    Fortune &operator=(const Fortune &other);
+
+    static Fortune create(const QString &message);
+    static Fortune create(const QVariantMap &values);
+    static Fortune get(const uint &id);
+    static QList<Fortune> getAll();
+
+private:
+    QSharedDataPointer<FortuneObject> d;
+
+    TSqlObject *data();
+    const TSqlObject *data() const;
+};
+
+Q_DECLARE_METATYPE(Fortune)
+Q_DECLARE_METATYPE(QList<Fortune>)
+
+#endif // FORTUNE_H

+ 19 - 0
treefrog/models/models.pro

@@ -0,0 +1,19 @@
+TARGET = model
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += sql
+QT -= gui
+DEFINES += TF_DLL
+DESTDIR = ../lib
+INCLUDEPATH += ../helpers sqlobjects
+DEPENDPATH  += ../helpers sqlobjects
+LIBS += -L../lib -lhelper
+
+include(../appbase.pri)
+
+HEADERS += sqlobjects/fortuneobject.h
+HEADERS += fortune.h
+SOURCES += fortune.cpp
+HEADERS += sqlobjects/worldobject.h
+HEADERS += world.h
+SOURCES += world.cpp

+ 31 - 0
treefrog/models/sqlobjects/fortuneobject.h

@@ -0,0 +1,31 @@
+#ifndef FORTUNEOBJECT_H
+#define FORTUNEOBJECT_H
+
+#include <TSqlObject>
+#include <QSharedData>
+
+
+class T_MODEL_EXPORT FortuneObject : public TSqlObject, public QSharedData
+{
+public:
+    uint id;
+    QString message;
+
+    enum PropertyIndex {
+        Id = 0,
+        Message,
+    };
+
+    QString tableName() const { return QLatin1String("Fortune"); }
+    int primaryKeyIndex() const { return Id; }
+    int autoValueIndex() const { return Id; }
+
+private:    /*** Don't modify below this line ***/
+    Q_OBJECT
+    Q_PROPERTY(uint id READ getid WRITE setid)
+    T_DEFINE_PROPERTY(uint, id)
+    Q_PROPERTY(QString message READ getmessage WRITE setmessage)
+    T_DEFINE_PROPERTY(QString, message)
+};
+
+#endif // FORTUNEOBJECT_H

+ 31 - 0
treefrog/models/sqlobjects/worldobject.h

@@ -0,0 +1,31 @@
+#ifndef WORLDOBJECT_H
+#define WORLDOBJECT_H
+
+#include <TSqlObject>
+#include <QSharedData>
+
+
+class T_MODEL_EXPORT WorldObject : public TSqlObject, public QSharedData
+{
+public:
+    uint id;
+    int randomnumber;
+
+    enum PropertyIndex {
+        Id = 0,
+        Randomnumber,
+    };
+
+    QString tableName() const { return QLatin1String("World"); }
+    int primaryKeyIndex() const { return Id; }
+    int autoValueIndex() const { return Id; }
+
+private:    /*** Don't modify below this line ***/
+    Q_OBJECT
+    Q_PROPERTY(uint id READ getid WRITE setid)
+    T_DEFINE_PROPERTY(uint, id)
+    Q_PROPERTY(int randomnumber READ getrandomnumber WRITE setrandomnumber)
+    T_DEFINE_PROPERTY(int, randomnumber)
+};
+
+#endif // WORLDOBJECT_H

+ 85 - 0
treefrog/models/world.cpp

@@ -0,0 +1,85 @@
+#include <TreeFrogModel>
+#include "world.h"
+#include "worldobject.h"
+
+World::World()
+    : TAbstractModel(), d(new WorldObject)
+{
+    d->randomnumber = 0;
+}
+
+World::World(const World &other)
+    : TAbstractModel(), d(new WorldObject(*other.d))
+{ }
+
+World::World(const WorldObject &object)
+    : TAbstractModel(), d(new WorldObject(object))
+{ }
+
+World::~World()
+{
+    // If the reference count becomes 0,
+    // the shared data object 'WorldObject' is deleted.
+}
+
+uint World::id() const
+{
+    return d->id;
+}
+
+int World::randomnumber() const
+{
+    return d->randomnumber;
+}
+
+void World::setRandomnumber(int randomnumber)
+{
+    d->randomnumber = randomnumber;
+}
+
+World &World::operator=(const World &other)
+{
+    d = other.d;  // increments the reference count of the data
+    return *this;
+}
+
+World World::create(int randomnumber)
+{
+    WorldObject obj;
+    obj.randomnumber = randomnumber;
+    if (!obj.create()) {
+        obj.clear();
+    }
+    return World(obj);
+}
+
+World World::create(const QVariantMap &values)
+{
+    World model;
+    model.setProperties(values);
+    if (!model.d->create()) {
+        model.d->clear();
+    }
+    return model;
+}
+
+World World::get(const uint &id)
+{
+    TSqlORMapper<WorldObject> mapper;
+    return World(mapper.findByPrimaryKey(id));
+}
+
+QList<World> World::getAll()
+{
+    return tfGetModelListByCriteria<World, WorldObject>(TCriteria());
+}
+
+TSqlObject *World::data()
+{
+    return d.data();
+}
+
+const TSqlObject *World::data() const
+{
+    return d.data();
+}

+ 43 - 0
treefrog/models/world.h

@@ -0,0 +1,43 @@
+#ifndef WORLD_H
+#define WORLD_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QVariant>
+#include <QSharedDataPointer>
+#include <TGlobal>
+#include <TAbstractModel>
+
+class TSqlObject;
+class WorldObject;
+
+
+class T_MODEL_EXPORT World : public TAbstractModel
+{
+public:
+    World();
+    World(const World &other);
+    World(const WorldObject &object);
+    ~World();
+
+    uint id() const;
+    int randomnumber() const;
+    void setRandomnumber(int randomnumber);
+    World &operator=(const World &other);
+
+    static World create(int randomnumber);
+    static World create(const QVariantMap &values);
+    static World get(const uint &id);
+    static QList<World> getAll();
+
+private:
+    QSharedDataPointer<WorldObject> d;
+
+    TSqlObject *data();
+    const TSqlObject *data() const;
+};
+
+Q_DECLARE_METATYPE(World)
+Q_DECLARE_METATYPE(QList<World>)
+
+#endif // WORLD_H

+ 28 - 0
treefrog/public/403.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html> 
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Forbidden</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Forbidden</h3>
+    <p>Accessing the page or resource you were trying to reach is absolutely forbidden.</p>
+  </div>
+</body>
+</html>

+ 28 - 0
treefrog/public/404.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html> 
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Page Not Found</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Page Not Found</h3>
+    <p>The server has not found anything matching the Request-URI.</p>
+  </div>
+</body>
+</html>

+ 28 - 0
treefrog/public/413.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Request Entity Too Large</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Request Entity Too Large</h3>
+    <p>The server is refusing to process a request because the request entity is larger than the server is willing or able to process.</p>
+  </div>
+</body>
+</html>

+ 29 - 0
treefrog/public/500.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Internal Server Error</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Internal Server Error</h3>
+    <p>The server encountered an unexpected condition which prevented it from fulfilling the request.
+</p>
+  </div>
+</body>
+</html>

+ 36 - 0
treefrog/setup.py

@@ -0,0 +1,36 @@
+
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+##############
+# start(args)
+##############
+def start(args):
+  setup_util.replace_text("treefrog/config/database.ini", "HostName=.*", "HostName=" + args.database_host)
+
+  # 1. Generate Makefile
+  # 2. Compile applicaton
+  # 3. Clean log files
+  # 4. Start TreeFrog
+  try:
+    subprocess.check_call("qmake -r CONFIG+=release", shell=True, cwd="treefrog")
+    subprocess.check_call("make", shell=True, cwd="treefrog")
+    subprocess.check_call("rm -f log/*.log", shell=True, cwd="treefrog")
+    subprocess.check_call("treefrog -d " + home + "/FrameworkBenchmarks/treefrog", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+##############
+# stop()
+##############
+def stop():
+  try:
+    subprocess.call("treefrog -k abort " + home + "/FrameworkBenchmarks/treefrog", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 2 - 0
treefrog/treefrog.pro

@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = helpers models views controllers

+ 22 - 0
treefrog/views/_src/_src.pro

@@ -0,0 +1,22 @@
+TARGET = view
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += network xml
+QT -= gui
+DEFINES += TF_DLL
+INCLUDEPATH += ../../helpers ../../models
+DEPENDPATH  += ../../helpers ../../models
+DESTDIR = ../../lib
+LIBS += -L../../lib -lhelper -lmodel
+QMAKE_CLEAN = *.cpp source.list
+
+tmake.target = source.list
+tmake.commands = tmake -f ../../config/application.ini -v .. -d . -P
+tmake.depends = qmake
+QMAKE_EXTRA_TARGETS = tmake
+
+include(../../appbase.pri)
+!exists(source.list) {
+  system( $$tmake.commands )
+}
+include(source.list)

+ 30 - 0
treefrog/views/fortune/edit.erb

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(QVariantMap, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Editing Fortune</h1>
+
+<%== formTag(urla("save", fortune["id"]), Tf::Post) %>
+  <p>
+    <label>ID<br /><input type="text" name="fortune[id]" value="<%= fortune["id"] %>" readonly="readonly" /></label>
+  </p>
+  <p>
+    <label>Message<br /><input type="text" name="fortune[message]" value="<%= fortune["message"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Update" />
+  </p>
+</form>
+
+<%== linkTo("Show", urla("show", fortune["id"])) %> |
+<%== linkTo("Back", urla("index")) %>
+</body>
+</html>

+ 27 - 0
treefrog/views/fortune/entry.erb

@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(QVariantMap, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>New Fortune</h1>
+
+<%== formTag(urla("create"), Tf::Post) %>
+  <p>
+    <label>Message<br /><input name="fortune[message]" value="<%= fortune["message"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Create" />
+  </p>
+</form>
+
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>

+ 35 - 0
treefrog/views/fortune/index.erb

@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+
+<h1>Listing Fortune</h1>
+
+<%== linkTo("New entry", urla("entry")) %><br />
+<br />
+<table border="1" cellpadding="5" style="border: 1px #d0d0d0 solid; border-collapse: collapse;">
+  <tr>
+    <th>ID</th>
+    <th>Message</th>
+  </tr>
+<% tfetch(QList<Fortune>, fortuneList); %>
+<% for (QListIterator<Fortune> it(fortuneList); it.hasNext(); ) {
+     const Fortune &i = it.next(); %>
+  <tr>
+    <td><%= i.id() %></td>
+    <td><%= i.message() %></td>
+    <td>
+      <%== linkTo("Show", urla("show", i.id())) %>
+      <%== linkTo("Edit", urla("edit", i.id())) %>
+      <%== linkTo("Remove", urla("remove", i.id()), Tf::Post, "confirm('Are you sure?')") %>
+    </td>
+  </tr>
+<% } %>
+</table>
+
+</body>
+</html>

+ 21 - 0
treefrog/views/fortune/show.erb

@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(Fortune, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Showing Fortune</h1>
+<dt>ID</dt><dd><%= fortune.id() %></dd><br />
+<dt>Message</dt><dd><%= fortune.message() %></dd><br />
+
+<%== linkTo("Edit", urla("edit", fortune.id())) %> |
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>

+ 1 - 0
treefrog/views/mailer/.trim_mode

@@ -0,0 +1 @@
+0

+ 2 - 0
treefrog/views/views.pro

@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = _src

+ 30 - 0
treefrog/views/world/edit.erb

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<%#include "world.h" %>
+<% tfetch(QVariantMap, world); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Editing World</h1>
+
+<%== formTag(urla("save", world["id"]), Tf::Post) %>
+  <p>
+    <label>ID<br /><input type="text" name="world[id]" value="<%= world["id"] %>" readonly="readonly" /></label>
+  </p>
+  <p>
+    <label>Randomnumber<br /><input type="text" name="world[randomnumber]" value="<%= world["randomnumber"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Update" />
+  </p>
+</form>
+
+<%== linkTo("Show", urla("show", world["id"])) %> |
+<%== linkTo("Back", urla("index")) %>
+</body>
+</html>

部分文件因为文件数量过多而无法显示