Browse Source

Merge branch 'master' of https://github.com/raphaelbauer/FrameworkBenchmarks into PR688

Conflicts:
	ninja/src/main/java/hello/views/HelloFortuneController/index.ftl.html
Mike Smith 11 years ago
parent
commit
66b81091e0
68 changed files with 1548 additions and 728 deletions
  1. 0 0
      ninja-resin/.gitignore
  2. 12 1
      ninja-resin/README.md
  3. 0 0
      ninja-resin/__init__.py
  4. 3 2
      ninja-resin/benchmark_config
  5. 16 0
      ninja-resin/changelog.md
  6. 196 0
      ninja-resin/pom.xml
  7. 6 6
      ninja-resin/setup.py
  8. 0 0
      ninja-resin/source_code
  9. 35 0
      ninja-resin/src/main/java/conf/Routes.java
  10. 15 6
      ninja-resin/src/main/java/conf/application.conf
  11. 0 0
      ninja-resin/src/main/java/conf/messages.properties
  12. 78 0
      ninja-resin/src/main/java/controllers/HelloDbController.java
  13. 30 0
      ninja-resin/src/main/java/controllers/HelloFortuneController.java
  14. 3 7
      ninja-resin/src/main/java/controllers/HelloJsonController.java
  15. 2 2
      ninja-resin/src/main/java/controllers/HelloPlaintextController.java
  16. 35 0
      ninja-resin/src/main/java/controllers/SetupController.java
  17. 8 8
      ninja-resin/src/main/java/dao/FortuneDao.java
  18. 71 0
      ninja-resin/src/main/java/dao/SetupDao.java
  19. 26 0
      ninja-resin/src/main/java/dao/WorldDao.java
  20. 0 0
      ninja-resin/src/main/java/ehcache.xml
  21. 0 0
      ninja-resin/src/main/java/logback.xml
  22. 7 6
      ninja-resin/src/main/java/model/Fortune.java
  23. 2 1
      ninja-resin/src/main/java/model/World.java
  24. 20 0
      ninja-resin/src/main/java/views/HelloFortuneController/index.ftl.html
  25. 47 0
      ninja-resin/src/main/resources/META-INF/persistence.xml
  26. 0 0
      ninja-resin/src/main/webapp/WEB-INF/resin-web.xml
  27. 0 0
      ninja-resin/src/main/webapp/WEB-INF/web.xml
  28. 92 0
      ninja-resin/src/test/java/controllers/HelloDbControllerTest.java
  29. 37 0
      ninja-resin/src/test/java/controllers/HelloFortuneControllerTest.java
  30. 48 0
      ninja-resin/src/test/java/controllers/HelloJsonControllerTest.java
  31. 29 0
      ninja-resin/src/test/java/controllers/HelloPlaintextControllerTest.java
  32. 11 5
      ninja-standalone/README.md
  33. 7 6
      ninja-standalone/benchmark_config
  34. 155 141
      ninja-standalone/pom.xml
  35. 3 3
      ninja-standalone/setup.py
  36. 23 14
      ninja-standalone/src/main/java/conf/Routes.java
  37. 17 4
      ninja-standalone/src/main/java/conf/application.conf
  38. 0 0
      ninja-standalone/src/main/java/conf/messages.properties
  39. 78 0
      ninja-standalone/src/main/java/controllers/HelloDbController.java
  40. 30 0
      ninja-standalone/src/main/java/controllers/HelloFortuneController.java
  41. 3 7
      ninja-standalone/src/main/java/controllers/HelloJsonController.java
  42. 2 2
      ninja-standalone/src/main/java/controllers/HelloPlaintextController.java
  43. 35 0
      ninja-standalone/src/main/java/controllers/SetupController.java
  44. 8 8
      ninja-standalone/src/main/java/dao/FortuneDao.java
  45. 71 0
      ninja-standalone/src/main/java/dao/SetupDao.java
  46. 26 0
      ninja-standalone/src/main/java/dao/WorldDao.java
  47. 0 0
      ninja-standalone/src/main/java/ehcache.xml
  48. 0 50
      ninja-standalone/src/main/java/hello/controllers/HelloDbController.java
  49. 0 28
      ninja-standalone/src/main/java/hello/controllers/HelloFortuneController.java
  50. 0 21
      ninja-standalone/src/main/java/hello/dao/WorldDao.java
  51. 0 20
      ninja-standalone/src/main/java/hello/views/HelloFortuneController/index.ftl.html
  52. 0 0
      ninja-standalone/src/main/java/logback.xml
  53. 7 6
      ninja-standalone/src/main/java/model/Fortune.java
  54. 2 1
      ninja-standalone/src/main/java/model/World.java
  55. 20 0
      ninja-standalone/src/main/java/views/HelloFortuneController/index.ftl.html
  56. 26 13
      ninja-standalone/src/main/resources/META-INF/persistence.xml
  57. 92 0
      ninja-standalone/src/test/java/controllers/HelloDbControllerTest.java
  58. 37 0
      ninja-standalone/src/test/java/controllers/HelloFortuneControllerTest.java
  59. 48 0
      ninja-standalone/src/test/java/controllers/HelloJsonControllerTest.java
  60. 29 0
      ninja-standalone/src/test/java/controllers/HelloPlaintextControllerTest.java
  61. 0 157
      ninja/pom.xml
  62. 0 26
      ninja/src/main/java/conf/Routes.java
  63. 0 50
      ninja/src/main/java/hello/controllers/HelloDbController.java
  64. 0 28
      ninja/src/main/java/hello/controllers/HelloFortuneController.java
  65. 0 21
      ninja/src/main/java/hello/dao/WorldDao.java
  66. 0 20
      ninja/src/main/java/hello/views/HelloFortuneController/index.ftl.html
  67. 0 45
      ninja/src/main/resources/META-INF/persistence.xml
  68. 0 13
      ninja/src/main/webapp/WEB-INF/resin-web.xml

+ 0 - 0
ninja/.gitignore → ninja-resin/.gitignore


+ 12 - 1
ninja/README.md → ninja-resin/README.md

@@ -2,6 +2,13 @@
 
 This is the [Ninja](http://www.ninjaframework.org/) portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
+## IMPORTANT!!!!
+
+ninja-resin is in essence just a copy of ninja-standalone with different datasources.
+That means all stuff you change in ninja-resin should also be applied to 
+ninja-standalone and vice-versa.
+
+
 ## Test URLs
 ### JSON Encoding Test
 
@@ -13,12 +20,16 @@ http://localhost:8080/ninja/db
 
 ### Multiple Queries Test
 
-http://localhost:8080/ninja/queries/5
+http://localhost:8080/ninja/queries?5
 
 ### Fortunes Test
 
 http://localhost:8080/ninja/fotunes
 
+### Update Test
+
+http://localhost:8080/ninja/update?5
+
 ### Plaintext Test
 
 http://localhost:8080/ninja/plaintext

+ 0 - 0
ninja/__init__.py → ninja-resin/__init__.py


+ 3 - 2
ninja/benchmark_config → ninja-resin/benchmark_config

@@ -5,8 +5,9 @@
       "setup_file": "setup",
       "json_url": "/ninja/json",
       "db_url": "/ninja/db",
-      "query_url": "/ninja/queries/",
+      "query_url": "/ninja/queries?queries=",
       "fortune_url": "/ninja/fortunes",
+      "update_url": "/ninja/update?queries=",
       "plaintext_url": "/ninja/plaintext",
       "port": 8080,
       "approach": "Realistic",
@@ -19,7 +20,7 @@
       "webserver": "Resin",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "ninja",
+      "display_name": "ninja-resin",
       "notes": "",
       "versus": "servlet"
     }

+ 16 - 0
ninja-resin/changelog.md

@@ -0,0 +1,16 @@
+Changelog 
+=========
+
+Because ninja-standalone and ninja-resin are almost identical this changelog
+applies to both.
+
+ * 2013-01-08 Performance improvement for Json Afterburner now active by default (from 2.5.1 onwards)
+ * 2013-01-08 Performance improvement for Db: Replaced @Transactional with @UnitOfWork for read only db operations (from 2.5.1 onwards)
+ * 2013-01-08 Reformatted and restructured some code
+ * 2013-01-08 Make sure Ninja is running in production mode (faster templates)
+ * 2013-01-08 Bump to Ninja 2.5.1
+ * 2013-12-13 Removed route that is never used in tests.
+ * 2013-12-14 Bump to Ninja 2.4.0.
+ * 2013-12-14 Added testcases and support for h2 in memory to develop locally with
+              in memory db.
+ * 2013-12-14 Added support for "updates" benchmark.

+ 196 - 0
ninja-resin/pom.xml

@@ -0,0 +1,196 @@
+<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.ninjaframework.techempower</groupId>
+    <artifactId>ninja-resin</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>ninja-resin</name>
+    <description>Ninja test for the TechEmpower/FrameworkBenchmarks project</description>
+
+    <properties>
+        <java.version>1.7</java.version>
+        <ninja.version>2.5.1</ninja.version>
+        <mysql.version>5.1.26</mysql.version>
+        <jetty.version>9.0.5.v20130815</jetty.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        
+        <!-- Ninja uses Guava 15.0 and Guava 15.0 by default has problems
+             with Resin (and other EE6 containers). Therefore we
+             force the usage of the following dependency which overwrites
+             the original one.
+             More here: https://code.google.com/p/guava-libraries/issues/detail?id=1527
+             -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>15.0</version>
+            <classifier>cdi1.0</classifier>
+        </dependency>
+
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-standalone</artifactId>
+            <version>${ninja.version}</version>
+            <exclusions>
+                <!-- See the comment above why we exclude guava -->
+                <exclusion>
+                    <groupId>com.google.guava </groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-test-utilities</artifactId>
+            <version>${ninja.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>${mysql.version}</version>
+        </dependency>
+                
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.174</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+			
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <warName>ninja</warName>
+                    <!-- Because seomhow in Techempower's platform the nasty
+                         guava default version still gets included we exlude
+                         it by force in the war file -->
+                    <packagingExcludes>WEB-INF/lib/guava-15.0.jar</packagingExcludes>
+                </configuration>
+            </plugin>
+            
+            <plugin>
+                <groupId>org.ninjaframework</groupId>
+                <artifactId>ninja-maven-plugin</artifactId>
+                <version>${ninja.version}</version>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <id>enforce-banned-dependencies</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <bannedDependencies>
+                                    <excludes>
+                                        <exclude>commons-logging</exclude>
+                                    </excludes>
+                                </bannedDependencies>
+                            </rules>
+                            <fail>true</fail>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-maven-plugin</artifactId>
+                <version>${jetty.version}</version>
+                <configuration>
+                    <contextPath>/</contextPath>
+                    <stopKey>stop</stopKey>
+                    <stopPort>8889</stopPort>
+                    <scanIntervalSeconds>1</scanIntervalSeconds>
+                    <reload>automatic</reload>
+                    <scanTargetPatterns>
+                        <scanTargetPattern>
+                            <directory>target/classes</directory>
+                            <includes>
+                                <include>**/*</include>
+                            </includes>
+                            <excludes>
+                                <exclude>**/*.ftl.html</exclude>
+                                <exclude>assets/**</exclude>
+                            </excludes>
+                        </scanTargetPattern>
+                    </scanTargetPatterns>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>2.7</version>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <archive>
+                        <manifest>
+                            <mainClass>ninja.standalone.NinjaJetty</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+</project>

+ 6 - 6
ninja/setup.py → ninja-resin/setup.py

@@ -4,20 +4,20 @@ import setup_util
 import os
 
 def start(args, logfile, errfile):
-  setup_util.replace_text("ninja/src/main/webapp/WEB-INF/resin-web.xml", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
+  setup_util.replace_text("ninja-resin/src/main/webapp/WEB-INF/resin-web.xml", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
   
   try:
-    subprocess.check_call("mvn clean compile war:war", shell=True, cwd="ninja", stderr=errfile, stdout=logfile)
+    subprocess.check_call("mvn clean compile war:war", shell=True, cwd="ninja-resin", stderr=errfile, stdout=logfile)
 
     if os.name == 'nt':
       subprocess.check_call('rmdir /S /Q "%RESIN_HOME%\\webapps\\"', shell=True, stderr=errfile, stdout=logfile)
       subprocess.check_call('mkdir "%RESIN_HOME%\\webapps\\"', shell=True, stderr=errfile, stdout=logfile)
-      subprocess.check_call('copy ninja\\target\\ninja.war "%RESIN_HOME%\\webapps\\ninja.war"', shell=True, stderr=errfile, stdout=logfile)
-      subprocess.check_call('"%RESIN_HOME%\\bin\\start.bat -Dninja.mode=prod"', shell=True, stderr=errfile, stdout=logfile)
+      subprocess.check_call('copy ninja-resin\\target\\ninja.war "%RESIN_HOME%\\webapps\\ninja.war"', shell=True, stderr=errfile, stdout=logfile)
+      subprocess.check_call('"%RESIN_HOME%\\bin\\start.bat"', shell=True, stderr=errfile, stdout=logfile)
     else:
       subprocess.check_call("rm -rf $RESIN_HOME/webapps/*", shell=True, stderr=errfile, stdout=logfile)
-      subprocess.check_call("cp ninja/target/ninja.war $RESIN_HOME/webapps/ninja.war", shell=True, stderr=errfile, stdout=logfile)
-      subprocess.check_call("$RESIN_HOME/bin/resinctl start -Dninja.mode=prod", shell=True, stderr=errfile, stdout=logfile)
+      subprocess.check_call("cp ninja-resin/target/ninja.war $RESIN_HOME/webapps/ninja.war", shell=True, stderr=errfile, stdout=logfile)
+      subprocess.check_call("$RESIN_HOME/bin/resinctl start", shell=True, stderr=errfile, stdout=logfile)
     return 0
   except subprocess.CalledProcessError:
     return 1

+ 0 - 0
ninja/source_code → ninja-resin/source_code


+ 35 - 0
ninja-resin/src/main/java/conf/Routes.java

@@ -0,0 +1,35 @@
+package conf;
+
+import com.google.inject.Inject;
+import controllers.HelloDbController;
+import controllers.HelloFortuneController;
+import controllers.HelloJsonController;
+import controllers.HelloPlaintextController;
+import controllers.SetupController;
+import ninja.Router;
+import ninja.application.ApplicationRoutes;
+import ninja.utils.NinjaProperties;
+
+public class Routes implements ApplicationRoutes {
+
+    @Inject
+    NinjaProperties ninjaProperties;
+
+    @Override
+    public void init(Router router) {
+
+        router.GET().route("/plaintext").with(HelloPlaintextController.class, "index");
+        router.GET().route("/json").with(HelloJsonController.class, "index");
+        router.GET().route("/queries").with(HelloDbController.class, "multiGet");
+        router.GET().route("/db").with(HelloDbController.class, "singleGet");
+        router.GET().route("/fortunes").with(HelloFortuneController.class, "index");
+        router.GET().route("/update").with(HelloDbController.class, "update");
+
+        // This route is only active when developing the app in dev mode
+        // e.g. when calling "mvn ninja:run".
+        if (ninjaProperties.isDev()) {
+            router.GET().route("/setupData").with(SetupController.class, "setupData");
+        }
+
+    }
+}

+ 15 - 6
ninja/src/main/resources/conf/application.conf → ninja-resin/src/main/java/conf/application.conf

@@ -17,7 +17,7 @@ application.name=ninja test application
 application.cookie.prefix=NINJA
 
 #ISO Language Code, optionally followed by a valid ISO Country Code. 
-application.languages=en,de
+application.languages=en
 
 application.session.expire_time_in_seconds=3600
 application.session.send_only_if_changed=true
@@ -30,11 +30,20 @@ application.session.transferred_over_https_only=false
 ##############################################################################
 ninja.migration.run=false
 
-ninja.jpa.persistence_unit_name = resin
+%prod.ninja.jpa.persistence_unit_name = resin
 
-%test.ninja.jpa.persistence_unit_name = mysql
-%test.db.connection.url=jdbc:mysql://localhost/hello_world
-%test.db.connection.username=benchmarkdbuser
-%test.db.connection.password=benchmarkdbpass
+## for eveloping locally:
+%dev.ninja.jpa.persistence_unit_name = h2
+## we are using a database stored in a file (in tests it is an in memory db)
+%dev.db.connection.url=jdbc:h2:target/h2database
+%dev.db.connection.username=ra
+%dev.db.connection.password=
+
+## for testing
+%test.ninja.jpa.persistence_unit_name = h2
+# in memory database for testing...
+%test.db.connection.url=jdbc:h2:mem:
+%test.db.connection.username=ra
+%test.db.connection.password=
 
 application.secret = b9z4AQO0huDRrJXFVjNiNXmSVqPSbcqjEiNjdPVBApb8n9GnxVjWBr9jp8tRfe73

+ 0 - 0
ninja-standalone/src/main/resources/conf/messages.properties → ninja-resin/src/main/java/conf/messages.properties


+ 78 - 0
ninja-resin/src/main/java/controllers/HelloDbController.java

@@ -0,0 +1,78 @@
+package controllers;
+
+import dao.WorldDao;
+import model.World;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import ninja.jpa.UnitOfWork;
+import ninja.params.Param;
+
+@Singleton
+public class HelloDbController {
+
+    private static final int DB_ROWS = 10000;
+    private final Random random = ThreadLocalRandom.current();
+
+    @Inject
+    WorldDao worldDao;
+
+    @UnitOfWork
+    public Result singleGet() {
+        return Results.json().render(getRandomWorld());
+    }
+
+    @UnitOfWork
+    public Result multiGet(@Param("queries") Integer queries) {
+        if (queries == null || queries < 1) {
+            queries = 1;
+        }
+        if (queries > 500) {
+            queries = 500;
+        }
+
+        final World[] worlds = new World[queries];
+
+        for (int i = 0; i < queries; i++) {
+            worlds[i] = getRandomWorld();
+        }
+
+        return Results.json().render(worlds);
+    }
+
+    @Transactional
+    public Result update(@Param("queries") Integer queries) {
+        if (queries == null || queries < 1) {
+            queries = 1;
+        }
+        if (queries > 500) {
+            queries = 500;
+        }
+
+        final World[] worlds = new World[queries];
+
+        for (int i = 0; i < queries; i++) {
+            worlds[i] = getRandomWorld();
+        }
+
+        // now update stuff:
+        for (World world : worlds) {
+            world.randomNumber = random.nextInt();
+            worldDao.put(world);
+        }
+
+        return Results.json().render(worlds);
+    }
+
+    private World getRandomWorld() {
+        return worldDao.get(random.nextInt(DB_ROWS) + 1);
+    }
+
+}

+ 30 - 0
ninja-resin/src/main/java/controllers/HelloFortuneController.java

@@ -0,0 +1,30 @@
+package controllers;
+
+import dao.FortuneDao;
+import model.Fortune;
+
+import java.util.Collections;
+import java.util.List;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import ninja.jpa.UnitOfWork;
+
+@Singleton
+public class HelloFortuneController {
+
+    @Inject
+    FortuneDao fortuneDao;
+
+    @UnitOfWork
+    public Result index() {
+        List<Fortune> fortunes = fortuneDao.getAll();
+        fortunes.add(new Fortune(0, "Additional fortune added at request time."));
+        Collections.sort(fortunes);
+
+        return Results.html().render("fortunes", fortunes);
+    }
+}

+ 3 - 7
ninja/src/main/java/hello/controllers/HelloJsonController.java → ninja-resin/src/main/java/controllers/HelloJsonController.java

@@ -1,4 +1,4 @@
-package hello.controllers;
+package controllers;
 
 import ninja.Result;
 import ninja.Results;
@@ -12,16 +12,12 @@ public class HelloJsonController {
 	return Results.json().render(new Message("Hello, World!"));
     }
 
-    public static class Message {
+    public final static class Message {
 
-	private final String message;
+	public final String message;
 
 	public Message(String message) {
 	    this.message = message;
 	}
-
-	public String getMessage() {
-	    return message;
-	}
     }
 }

+ 2 - 2
ninja/src/main/java/hello/controllers/HelloPlaintextController.java → ninja-resin/src/main/java/controllers/HelloPlaintextController.java

@@ -1,4 +1,4 @@
-package hello.controllers;
+package controllers;
 
 import ninja.Result;
 import ninja.Results;
@@ -8,6 +8,6 @@ import com.google.inject.Singleton;
 @Singleton
 public class HelloPlaintextController {
     public Result index() {
-	return Results.html().renderRaw("Hello, world!");
+	return Results.text().renderRaw("Hello, world!");
     }
 }

+ 35 - 0
ninja-resin/src/main/java/controllers/SetupController.java

@@ -0,0 +1,35 @@
+package controllers;
+
+import dao.WorldDao;
+import model.World;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dao.SetupDao;
+
+@Singleton
+public class SetupController {
+
+    @Inject
+    SetupDao setupDao;
+
+    public Result setupData() {
+        
+        setupDao.deleteAllData();
+        
+        setupDao.generateWorldsForTest();
+        setupDao.generateFortunesForTest();
+        
+        return Results.text().render("setup done");
+        
+    }
+    
+   
+
+}

+ 8 - 8
ninja/src/main/java/hello/dao/FortuneDao.java → ninja-resin/src/main/java/dao/FortuneDao.java

@@ -1,6 +1,6 @@
-package hello.dao;
+package dao;
 
-import hello.model.Fortune;
+import model.Fortune;
 
 import java.util.List;
 
@@ -9,21 +9,21 @@ import javax.persistence.Query;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.persist.Transactional;
+import com.google.inject.Singleton;
 
+@Singleton
 public class FortuneDao {
 
     @Inject
     Provider<EntityManager> entitiyManagerProvider;
 
-    @Transactional
     public List<Fortune> getAll() {
-	EntityManager entityManager = entitiyManagerProvider.get();
+        EntityManager entityManager = entitiyManagerProvider.get();
 
-	Query q = entityManager.createQuery("SELECT x FROM Fortune x");
-	List<Fortune> fortunes = q.getResultList();
+        Query q = entityManager.createQuery("SELECT x FROM Fortune x");
+        List<Fortune> fortunes = q.getResultList();
 
-	return fortunes;
+        return fortunes;
     }
 
 }

+ 71 - 0
ninja-resin/src/main/java/dao/SetupDao.java

@@ -0,0 +1,71 @@
+package dao;
+
+import model.Fortune;
+
+import javax.persistence.EntityManager;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import java.util.List;
+import javax.persistence.Query;
+import model.World;
+
+/**
+ * This class is just for testing. Has nothing to do with the TechEmpower test
+ * itself...
+ *
+ * @author ra
+ */
+@Singleton
+public class SetupDao {
+
+    @Inject
+    Provider<EntityManager> entitiyManagerProvider;
+
+    @Transactional
+    public void deleteAllData() {
+
+        entitiyManagerProvider.get().createQuery("DELETE FROM World");
+        entitiyManagerProvider.get().createQuery("DELETE FROM Fortune");
+
+    }
+
+    @Transactional
+    public void generateWorldsForTest() {
+
+        for (int i = 0; i < 10000; i++) {
+
+            World world = new World();
+            world.randomNumber = i; // not really a random number. But we can test with that...
+            entitiyManagerProvider.get().persist(world);
+
+        }
+
+    }
+
+    @Transactional
+    public void generateFortunesForTest() {
+
+        {
+
+            Fortune fortune = new Fortune();
+            // dummy message => just to make sure utf-8 works.
+            fortune.message = "レームワークのベンチマーク";
+            entitiyManagerProvider.get().persist(fortune);
+
+        }
+
+        {
+
+            Fortune fortune = new Fortune();
+            // dummy message => just to make sure utf-8 works.
+            fortune.message = "<script>I want to be escaped</script>";
+            entitiyManagerProvider.get().persist(fortune);
+
+        }
+
+    }
+
+}

+ 26 - 0
ninja-resin/src/main/java/dao/WorldDao.java

@@ -0,0 +1,26 @@
+package dao;
+
+import model.World;
+
+import javax.persistence.EntityManager;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class WorldDao {
+
+    @Inject
+    Provider<EntityManager> entitiyManagerProvider;
+
+    public World get(int id) {
+        EntityManager entityManager = entitiyManagerProvider.get();
+        return entityManager.find(World.class, id);
+    }
+
+    public void put(World world) {
+        EntityManager entityManager = entitiyManagerProvider.get();
+        entityManager.persist(world);
+    }
+}

+ 0 - 0
ninja-standalone/src/main/resources/ehcache.xml → ninja-resin/src/main/java/ehcache.xml


+ 0 - 0
ninja-standalone/src/main/resources/logback.xml → ninja-resin/src/main/java/logback.xml


+ 7 - 6
ninja-standalone/src/main/java/hello/model/Fortune.java → ninja-resin/src/main/java/model/Fortune.java

@@ -1,4 +1,4 @@
-package hello.model;
+package model;
 
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -7,6 +7,7 @@ import javax.persistence.Id;
 
 @Entity
 public class Fortune implements Comparable<Fortune> {
+
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     public int id;
@@ -17,20 +18,20 @@ public class Fortune implements Comparable<Fortune> {
     }
 
     public Fortune(int id, String message) {
-	this.id = id;
-	this.message = message;
+        this.id = id;
+        this.message = message;
     }
 
     public int getId() {
-	return this.id;
+        return this.id;
     }
 
     public String getMessage() {
-	return this.message;
+        return this.message;
     }
 
     @Override
     public int compareTo(Fortune other) {
-	return message.compareTo(other.message);
+        return message.compareTo(other.message);
     }
 }

+ 2 - 1
ninja-standalone/src/main/java/hello/model/World.java → ninja-resin/src/main/java/model/World.java

@@ -1,4 +1,4 @@
-package hello.model;
+package model;
 
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -7,6 +7,7 @@ import javax.persistence.Id;
 
 @Entity
 public class World {
+
     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     public int id;

+ 20 - 0
ninja-resin/src/main/java/views/HelloFortuneController/index.ftl.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <table>
+            <tr>
+                <th>id</th>
+                <th>message</th>
+            </tr>
+            <#list fortunes as fortune>
+            <tr>
+                <td>${fortune.id}</td>
+                <td>${fortune.message}</td>
+            </tr>
+            </#list>
+        </table>
+    </body>
+</html>

+ 47 - 0
ninja-resin/src/main/resources/META-INF/persistence.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+             version="2.0">
+    
+    <!-- Resin datasource -->
+    <persistence-unit name="resin" transaction-type="RESOURCE_LOCAL">
+        <provider>org.hibernate.ejb.HibernatePersistence</provider>
+        <jta-data-source>java:comp/env/jdbc/hello_world</jta-data-source>
+
+        <properties>
+            <property name="hibernate.connection.datasource" value="java:comp/env/jdbc/hello_world" />
+            <property name="hibernate.transaction.factory_class"
+                                  value="org.hibernate.transaction.JTATransactionFactory" />
+            <property name="hibernate.transaction.manager_lookup_class"
+                                  value="org.hibernate.transaction.ResinTransactionManagerLookup" />
+        </properties>
+    </persistence-unit>
+        
+    <!-- Database for tests and local dev mode... -->
+    <persistence-unit name="h2" transaction-type="RESOURCE_LOCAL">
+        <provider>org.hibernate.ejb.HibernatePersistence</provider>
+        <properties>
+            <property name="javax.persistence.provider" value="org.hibernate.ejb.HibernatePersistence" />
+            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
+            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
+            <!-- you may want to enable the ddl if you do not use migrations. -->
+            <property name="hibernate.hbm2ddl.auto" value="create" />
+            <property name="hibernate.show_sql" value="false" />
+            <property name="hibernate.format_sql" value="false" />
+
+            <!-- Connection Pooling settings -->
+            <property name="hibernate.connection.provider_class"
+                          value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
+
+            <property name="hibernate.c3p0.max_size" value="100" />
+            <property name="hibernate.c3p0.min_size" value="0" />
+            <property name="hibernate.c3p0.acquire_increment" value="1" />
+            <property name="hibernate.c3p0.idle_test_period" value="300" />
+            <property name="hibernate.c3p0.max_statements" value="0" />
+            <property name="hibernate.c3p0.timeout" value="100" />     
+        </properties>
+    </persistence-unit>
+
+</persistence>

+ 0 - 0
ninja-standalone/src/main/webapp/WEB-INF/resin-web.xml → ninja-resin/src/main/webapp/WEB-INF/resin-web.xml


+ 0 - 0
ninja/src/main/webapp/WEB-INF/web.xml → ninja-resin/src/main/webapp/WEB-INF/web.xml


+ 92 - 0
ninja-resin/src/test/java/controllers/HelloDbControllerTest.java

@@ -0,0 +1,92 @@
+package controllers;
+
+import dao.SetupDao;
+import model.World;
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+public class HelloDbControllerTest extends NinjaDocTester {
+            
+    String URL_DB = "/db";
+    String URL_QUERIES = "/queries";
+    String URL_UPDATE = "/update";
+    
+    @Before
+    public void setupClass() {
+        getInjector().getInstance(SetupDao.class).generateWorldsForTest();
+    }
+    
+    @Test
+    public void testSingleGet() {
+        
+        Response response = makeRequest(
+                Request
+                        .GET()
+                        .url(testServerUrl().path(URL_DB))
+                        .contentTypeApplicationJson());
+        
+        // Just make sure that we get back a World Json.
+        assertThat(response.payloadAs(World.class), notNullValue());      
+                
+    }
+    
+    @Test
+    public void multipleQueries() {
+        
+        assertThatMutipleGetWorksFor(1);
+        assertThatMutipleGetWorksFor(5);
+        assertThatMutipleGetWorksFor(10);
+        assertThatMutipleGetWorksFor(15);
+        assertThatMutipleGetWorksFor(20);
+                
+    }
+    
+    private void assertThatMutipleGetWorksFor(int numberOfQueries) {
+        Response response = makeRequest(
+            Request
+                .GET()
+                .url(
+                    testServerUrl()
+                    .path(URL_QUERIES)
+                    .addQueryParameter("queries", numberOfQueries + ""))
+                .contentTypeApplicationJson());
+        
+        // Just make sure that we get back an array
+        assertThat(response.payloadAs(World[].class).length, is(numberOfQueries)); 
+    }
+    
+    @Test
+    public void testUpdates() {
+        
+        assertThatUpdateWorks(1);
+        assertThatUpdateWorks(5);
+        assertThatUpdateWorks(10);
+        assertThatUpdateWorks(15);
+        assertThatUpdateWorks(20);
+                
+    }
+    
+    private void assertThatUpdateWorks(int numberOfQueries) {
+        
+        Response response = makeRequest(
+            Request.GET()
+                .url(
+                    testServerUrl()
+                    .path(URL_UPDATE)
+                    .addQueryParameter("queries", numberOfQueries + ""))
+                .contentTypeApplicationJson());
+        
+        assertThat(response.payloadAs(World[].class).length, is(numberOfQueries)); 
+        
+    }
+
+    
+    
+}

+ 37 - 0
ninja-resin/src/test/java/controllers/HelloFortuneControllerTest.java

@@ -0,0 +1,37 @@
+package controllers;
+
+import dao.SetupDao;
+import model.Fortune;
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class HelloFortuneControllerTest extends NinjaDocTester {
+
+    String URL_FORTUNES = "/fortunes";
+    
+    @Test
+    public void testSomeMethod() {
+        
+        getInjector().getInstance(SetupDao.class).generateFortunesForTest();
+
+        Response response 
+                = makeRequest(Request.GET().url(testServerUrl().path(URL_FORTUNES)));
+        
+        System.out.println(" " + response.payload);
+        
+        // make sure escaping works
+        assertTrue(response.payload.contains("&lt;script&gt;I want to be escaped&lt;/script&gt;"));
+
+        // make sure utf-8 works
+        assertTrue(response.payload.contains("レームワークのベンチマーク<"));
+        
+        // make sure new Fortune has been added to response
+        assertTrue(response.payload.contains("Additional fortune added at request time."));
+
+        
+    }
+    
+}

+ 48 - 0
ninja-resin/src/test/java/controllers/HelloJsonControllerTest.java

@@ -0,0 +1,48 @@
+package controllers;
+
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+public class HelloJsonControllerTest extends NinjaDocTester {
+    
+    String URL_JSON = "/json";
+
+    @Test
+    public void testHelloJsonController() {
+        
+        Response response = makeRequest(
+            Request
+                .GET()
+                .url(testServerUrl().path(URL_JSON))
+                .contentTypeApplicationJson());
+        
+        assertThat(
+            response.payloadAs(Message.class).message, 
+            is("Hello, world"));
+        
+    }
+    
+    /**
+     * Duplicated from HelloJsonController.
+     * 
+     * Stuff in HelloJsonController is final, but to deserialize the message we
+     * need an empty constructor...
+     */
+    public final static class Message {
+
+	public String message;
+        
+	public Message() {}
+
+	public Message(String message) {
+	    this.message = message;
+	}
+    }
+    
+}

+ 29 - 0
ninja-resin/src/test/java/controllers/HelloPlaintextControllerTest.java

@@ -0,0 +1,29 @@
+package controllers;
+
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class HelloPlaintextControllerTest extends NinjaDocTester {
+    
+    String URL_PLAINTEXT = "/plaintext";
+    
+    @Test
+    public void helloPlaintextControllerTest() {
+        
+        Response response = makeRequest(
+            Request.GET().url(testServerUrl().path(URL_PLAINTEXT)));
+        
+        assertThat(response.payload, CoreMatchers.is("Hello, world!"));
+        assertThat(
+            response.headers.get("Content-Type"), 
+            is("text/plain; charset=UTF-8"));
+        
+   
+    }
+    
+}

+ 11 - 5
ninja-standalone/README.md

@@ -2,25 +2,31 @@
 
 This is the [Ninja-standalone](http://www.ninjaframework.org/) portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
+## IMPORTANT!!!!
+
+ninja-resin is in essence just a copy of ninja-standalone with different datasources.
+That means all stuff you change in ninja-resin should also be applied to 
+ninja-standalone and vice-versa.
+
 ## Test URLs
 ### JSON Encoding Test
 
-http://localhost:8080/ninja/json
+http://localhost:8080/json
 
 ### Single Query Test
 
-http://localhost:8080/ninja/db
+http://localhost:8080/db
 
 ### Multiple Queries Test
 
-http://localhost:8080/ninja/queries/5
+http://localhost:8080/queries?5
 
 ### Fortunes Test
 
-http://localhost:8080/ninja/fotunes
+http://localhost:8080/fotunes
 
 ### Plaintext Test
 
-http://localhost:8080/ninja/plaintext
+http://localhost:8080/plaintext
 
 

+ 7 - 6
ninja-standalone/benchmark_config

@@ -1,13 +1,14 @@
 {
-  "framework": "ninja",
+  "framework": "ninja-standalone",
   "tests": [{
     "default": {
       "setup_file": "setup",
-      "json_url": "/ninja/json",
-      "db_url": "/ninja/db",
-      "query_url": "/ninja/queries/",
-      "fortune_url": "/ninja/fortunes",
-      "plaintext_url": "/ninja/plaintext",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Fullstack",

+ 155 - 141
ninja-standalone/pom.xml

@@ -1,163 +1,177 @@
 <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>helo.world</groupId>
-	<artifactId>hello-ninja-standalone</artifactId>
-	<version>0.0.1-SNAPSHOT</version>
-	<name>Ninja Framework Test Project</name>
-	<description>Nnja test for the TechEmpower/FrameworkBenchmarks project</description>
+         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.ninjaframework.techempower</groupId>
+    <artifactId>ninja-standalone</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>ninja-standalone</name>
+    <description>Ninja test for the TechEmpower/FrameworkBenchmarks project</description>
 
-	<properties>
-		<java-version>1.7</java-version>
-		<ninja.version>2.1.0</ninja.version>
-		<mysql.version>5.1.26</mysql.version>
-		<jetty.version>9.0.5.v20130815</jetty.version>
-	</properties>
+    <properties>
+        <java-version>1.7</java-version>
+        <ninja.version>2.5.1</ninja.version>
+        <mysql.version>5.1.26</mysql.version>
+        <jetty.version>9.0.5.v20130815</jetty.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
 
-	<dependencies>
-		<dependency>
-			<groupId>org.ninjaframework</groupId>
-			<artifactId>ninja-servlet</artifactId>
-			<version>${ninja.version}</version>
-		</dependency>
+    <dependencies>
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-servlet</artifactId>
+            <version>${ninja.version}</version>
+        </dependency>
 
-    		<dependency>
-        		<groupId>org.ninjaframework</groupId>
-        		<artifactId>ninja-standalone</artifactId>
-        		<version>${ninja.version}</version>
-    		</dependency>   
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-standalone</artifactId>
+            <version>${ninja.version}</version>
+        </dependency>   
 
-		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>javax.servlet-api</artifactId>
-			<version>3.0.1</version>
-			<scope>provided</scope>
-		</dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.0.1</version>
+            <scope>provided</scope>
+        </dependency>
 
-		<dependency>
-			<groupId>org.ninjaframework</groupId>
-			<artifactId>ninja-test-utilities</artifactId>
-			<version>${ninja.version}</version>
-			<scope>test</scope>
-		</dependency>
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-test-utilities</artifactId>
+            <version>${ninja.version}</version>
+            <scope>test</scope>
+        </dependency>
 
-		<dependency>
-			<groupId>mysql</groupId>
-			<artifactId>mysql-connector-java</artifactId>
-			<version>${mysql.version}</version>
-		</dependency>
-	</dependencies>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>${mysql.version}</version>
+        </dependency>
+                        
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.174</version>
+        </dependency>
+    </dependencies>
 
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-compiler-plugin</artifactId>
-				<version>3.1</version>
-				<configuration>
-					<source>${java-version}</source>
-					<target>${java-version}</target>
-				</configuration>
-			</plugin>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java-version}</source>
+                    <target>${java-version}</target>
+                </configuration>
+            </plugin>
 			
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-war-plugin</artifactId>
+                <version>2.4</version>
                 <configuration>
                     <warName>ninja</warName>
                 </configuration>
             </plugin>
+            
+            <plugin>
+                <groupId>org.ninjaframework</groupId>
+                <artifactId>ninja-maven-plugin</artifactId>
+                <version>${ninja.version}</version>
+            </plugin>
 
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-enforcer-plugin</artifactId>
-				<version>1.0</version>
-				<executions>
-					<execution>
-						<id>enforce-banned-dependencies</id>
-						<goals>
-							<goal>enforce</goal>
-						</goals>
-						<configuration>
-							<rules>
-								<bannedDependencies>
-									<excludes>
-										<exclude>commons-logging</exclude>
-									</excludes>
-								</bannedDependencies>
-							</rules>
-							<fail>true</fail>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <id>enforce-banned-dependencies</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <bannedDependencies>
+                                    <excludes>
+                                        <exclude>commons-logging</exclude>
+                                    </excludes>
+                                </bannedDependencies>
+                            </rules>
+                            <fail>true</fail>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
 
-			<plugin>
-				<groupId>org.eclipse.jetty</groupId>
-				<artifactId>jetty-maven-plugin</artifactId>
-				<version>${jetty.version}</version>
-				<configuration>
-					<contextPath>/</contextPath>
-					<stopKey>stop</stopKey>
-					<stopPort>8889</stopPort>
-					<scanIntervalSeconds>1</scanIntervalSeconds>
-					<reload>automatic</reload>
-					<scanTargetPatterns>
-						<scanTargetPattern>
-							<directory>target/classes</directory>
-							<includes>
-								<include>**/*</include>
-							</includes>
-							<excludes>
-								<exclude>**/*.ftl.html</exclude>
-								<exclude>assets/**</exclude>
-							</excludes>
-						</scanTargetPattern>
-					</scanTargetPatterns>
-				</configuration>
-			</plugin>
+            <plugin>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-maven-plugin</artifactId>
+                <version>${jetty.version}</version>
+                <configuration>
+                    <contextPath>/</contextPath>
+                    <stopKey>stop</stopKey>
+                    <stopPort>8889</stopPort>
+                    <scanIntervalSeconds>1</scanIntervalSeconds>
+                    <reload>automatic</reload>
+                    <scanTargetPatterns>
+                        <scanTargetPattern>
+                            <directory>target/classes</directory>
+                            <includes>
+                                <include>**/*</include>
+                            </includes>
+                            <excludes>
+                                <exclude>**/*.ftl.html</exclude>
+                                <exclude>assets/**</exclude>
+                            </excludes>
+                        </scanTargetPattern>
+                    </scanTargetPatterns>
+                </configuration>
+            </plugin>
 
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-deploy-plugin</artifactId>
-				<version>2.7</version>
-				<configuration>
-					<skip>true</skip>
-				</configuration>
-			</plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>2.7</version>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
 
-			<plugin>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<version>2.4</version>
-				<configuration>
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<mainClass>ninja.standalone.NinjaJetty</mainClass>
-						</manifest>
-					</archive>
-				</configuration>
-			</plugin>
-		</plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <archive>
+                        <manifest>
+                            <mainClass>ninja.standalone.NinjaJetty</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
 
-		<resources>
-			<resource>
-				<directory>src/main/java</directory>
-				<includes>
-					<include>**/*</include>
-				</includes>
-				<excludes>
-					<exclude>**/*.java</exclude>
-				</excludes>
-			</resource>
-			<resource>
-				<directory>src/main/resources</directory>
-				<includes>
-					<include>**/*</include>
-				</includes>
-			</resource>
-		</resources>
-	</build>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
 </project>

+ 3 - 3
ninja-standalone/setup.py

@@ -4,11 +4,11 @@ import setup_util
 import os
 
 def start(args, logfile, errfile):
-  setup_util.replace_text("ninja-standalone/src/main/resource/conf/application.conf", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
+  setup_util.replace_text("ninja-standalone/src/main/java/conf/application.conf", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
   
   try:
     subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="ninja-standalone", stderr=errfile, stdout=logfile)
-    subprocess.check_call("java -Dninja.port=8080 -Dninja.mode=prod -Dninja.context=/ninja -jar ninja-standalone/target/hello-ninja-standalone-0.0.1-SNAPSHOT-jar-with-dependencies.jar", shell=True, stderr=errfile, stdout=logfile)
+    subprocess.Popen("java -Dninja.port=8080 -jar target/ninja-standalone-0.0.1-SNAPSHOT-jar-with-dependencies.jar", cwd="ninja-standalone", shell=True, stderr=errfile, stdout=logfile)
     return 0
   except subprocess.CalledProcessError:
     return 1
@@ -17,7 +17,7 @@ def stop(logfile, errfile):
   p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
   out, err = p.communicate()
   for line in out.splitlines():
-    if 'hello-ninja' in line:
+    if 'ninja-standalone' in line:
       pid = int(line.split(None, 2)[1])
       os.kill(pid, 9)
   return 0

+ 23 - 14
ninja-standalone/src/main/java/conf/Routes.java

@@ -1,26 +1,35 @@
 package conf;
 
-import hello.controllers.HelloDbController;
-import hello.controllers.HelloFortuneController;
-import hello.controllers.HelloJsonController;
-import hello.controllers.HelloPlaintextController;
+import com.google.inject.Inject;
+import controllers.HelloDbController;
+import controllers.HelloFortuneController;
+import controllers.HelloJsonController;
+import controllers.HelloPlaintextController;
+import controllers.SetupController;
 import ninja.Router;
 import ninja.application.ApplicationRoutes;
+import ninja.utils.NinjaProperties;
 
 public class Routes implements ApplicationRoutes {
 
+    @Inject
+    NinjaProperties ninjaProperties;
+
     @Override
     public void init(Router router) {
 
-	router.GET().route("/").with(HelloPlaintextController.class, "index");
-	router.GET().route("/plaintext")
-		.with(HelloPlaintextController.class, "index");
-	router.GET().route("/json").with(HelloJsonController.class, "index");
-	router.GET().route("/queries/{queries}")
-		.with(HelloDbController.class, "multiGet");
-	router.GET().route("/db").with(HelloDbController.class, "singleGet");
-	router.GET().route("/fortunes")
-		.with(HelloFortuneController.class, "index");
+        router.GET().route("/plaintext").with(HelloPlaintextController.class, "index");
+        router.GET().route("/json").with(HelloJsonController.class, "index");
+        router.GET().route("/queries").with(HelloDbController.class, "multiGet");
+        router.GET().route("/db").with(HelloDbController.class, "singleGet");
+        router.GET().route("/fortunes").with(HelloFortuneController.class, "index");
+        router.GET().route("/update").with(HelloDbController.class, "update");
+
+        // This route is only active when developing the app in dev mode
+        // e.g. when calling "mvn ninja:run".
+        if (ninjaProperties.isDev()) {
+            router.GET().route("/setupData").with(SetupController.class, "setupData");
+        }
 
     }
-}
+}

+ 17 - 4
ninja-standalone/src/main/resources/conf/application.conf → ninja-standalone/src/main/java/conf/application.conf

@@ -30,9 +30,22 @@ application.session.transferred_over_https_only=false
 ##############################################################################
 ninja.migration.run=false
 
-ninja.jpa.persistence_unit_name = mysql
-db.connection.url=jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&amp;elideSetAutoCommits=true&amp;useLocalSessionState=true&amp;cachePrepStmts=true&amp;cacheCallableStmts=true&amp;alwaysSendSetIsolation=false&amp;prepStmtCacheSize=4096&amp;cacheServerConfiguration=true&amp;prepStmtCacheSqlLimit=2048&amp;zeroDateTimeBehavior=convertToNull&amp;traceProtocol=false&amp;useUnbufferedInput=false&amp;useReadAheadInput=false&amp;maintainTimeStats=false&amp;useServerPrepStmts&amp;cacheRSMetadata=true
-db.connection.username=benchmarkdbuser
-db.connection.password=benchmarkdbpass
+%prod.ninja.jpa.persistence_unit_name = mysql
+%prod.db.connection.url=jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&amp;elideSetAutoCommits=true&amp;useLocalSessionState=true&amp;cachePrepStmts=true&amp;cacheCallableStmts=true&amp;alwaysSendSetIsolation=false&amp;prepStmtCacheSize=4096&amp;cacheServerConfiguration=true&amp;prepStmtCacheSqlLimit=2048&amp;zeroDateTimeBehavior=convertToNull&amp;traceProtocol=false&amp;useUnbufferedInput=false&amp;useReadAheadInput=false&amp;maintainTimeStats=false&amp;useServerPrepStmts&amp;cacheRSMetadata=true
+%prod.db.connection.username=benchmarkdbuser
+%prod.db.connection.password=benchmarkdbpass
+
+## for testing and developing locally:
+%dev.ninja.jpa.persistence_unit_name = h2
+%dev.db.connection.url=jdbc:h2:target/h2database
+%dev.db.connection.username=ra
+%dev.db.connection.password=
+
+## for testing
+%test.ninja.jpa.persistence_unit_name = h2
+# in memory database for testing...
+%test.db.connection.url=jdbc:h2:mem:
+%test.db.connection.username=ra
+%test.db.connection.password=
 
 application.secret = b9z4AQO0huDRrJXFVjNiNXmSVqPSbcqjEiNjdPVBApb8n9GnxVjWBr9jp8tRfe73

+ 0 - 0
ninja/src/main/resources/conf/messages.properties → ninja-standalone/src/main/java/conf/messages.properties


+ 78 - 0
ninja-standalone/src/main/java/controllers/HelloDbController.java

@@ -0,0 +1,78 @@
+package controllers;
+
+import dao.WorldDao;
+import model.World;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import ninja.jpa.UnitOfWork;
+import ninja.params.Param;
+
+@Singleton
+public class HelloDbController {
+
+    private static final int DB_ROWS = 10000;
+    private final Random random = ThreadLocalRandom.current();
+
+    @Inject
+    WorldDao worldDao;
+
+    @UnitOfWork
+    public Result singleGet() {
+        return Results.json().render(getRandomWorld());
+    }
+
+    @UnitOfWork
+    public Result multiGet(@Param("queries") Integer queries) {
+        if (queries == null || queries < 1) {
+            queries = 1;
+        }
+        if (queries > 500) {
+            queries = 500;
+        }
+
+        final World[] worlds = new World[queries];
+
+        for (int i = 0; i < queries; i++) {
+            worlds[i] = getRandomWorld();
+        }
+
+        return Results.json().render(worlds);
+    }
+
+    @Transactional
+    public Result update(@Param("queries") Integer queries) {
+        if (queries == null || queries < 1) {
+            queries = 1;
+        }
+        if (queries > 500) {
+            queries = 500;
+        }
+
+        final World[] worlds = new World[queries];
+
+        for (int i = 0; i < queries; i++) {
+            worlds[i] = getRandomWorld();
+        }
+
+        // now update stuff:
+        for (World world : worlds) {
+            world.randomNumber = random.nextInt();
+            worldDao.put(world);
+        }
+
+        return Results.json().render(worlds);
+    }
+
+    private World getRandomWorld() {
+        return worldDao.get(random.nextInt(DB_ROWS) + 1);
+    }
+
+}

+ 30 - 0
ninja-standalone/src/main/java/controllers/HelloFortuneController.java

@@ -0,0 +1,30 @@
+package controllers;
+
+import dao.FortuneDao;
+import model.Fortune;
+
+import java.util.Collections;
+import java.util.List;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import ninja.jpa.UnitOfWork;
+
+@Singleton
+public class HelloFortuneController {
+
+    @Inject
+    FortuneDao fortuneDao;
+
+    @UnitOfWork
+    public Result index() {
+        List<Fortune> fortunes = fortuneDao.getAll();
+        fortunes.add(new Fortune(0, "Additional fortune added at request time."));
+        Collections.sort(fortunes);
+
+        return Results.html().render("fortunes", fortunes);
+    }
+}

+ 3 - 7
ninja-standalone/src/main/java/hello/controllers/HelloJsonController.java → ninja-standalone/src/main/java/controllers/HelloJsonController.java

@@ -1,4 +1,4 @@
-package hello.controllers;
+package controllers;
 
 import ninja.Result;
 import ninja.Results;
@@ -12,16 +12,12 @@ public class HelloJsonController {
 	return Results.json().render(new Message("Hello, World!"));
     }
 
-    public static class Message {
+    public final static class Message {
 
-	private final String message;
+	public final String message;
 
 	public Message(String message) {
 	    this.message = message;
 	}
-
-	public String getMessage() {
-	    return message;
-	}
     }
 }

+ 2 - 2
ninja-standalone/src/main/java/hello/controllers/HelloPlaintextController.java → ninja-standalone/src/main/java/controllers/HelloPlaintextController.java

@@ -1,4 +1,4 @@
-package hello.controllers;
+package controllers;
 
 import ninja.Result;
 import ninja.Results;
@@ -8,6 +8,6 @@ import com.google.inject.Singleton;
 @Singleton
 public class HelloPlaintextController {
     public Result index() {
-	return Results.html().renderRaw("Hello, world!");
+	return Results.text().renderRaw("Hello, world!");
     }
 }

+ 35 - 0
ninja-standalone/src/main/java/controllers/SetupController.java

@@ -0,0 +1,35 @@
+package controllers;
+
+import dao.WorldDao;
+import model.World;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dao.SetupDao;
+
+@Singleton
+public class SetupController {
+
+    @Inject
+    SetupDao setupDao;
+
+    public Result setupData() {
+        
+        setupDao.deleteAllData();
+        
+        setupDao.generateWorldsForTest();
+        setupDao.generateFortunesForTest();
+        
+        return Results.text().render("setup done");
+        
+    }
+    
+   
+
+}

+ 8 - 8
ninja-standalone/src/main/java/hello/dao/FortuneDao.java → ninja-standalone/src/main/java/dao/FortuneDao.java

@@ -1,6 +1,6 @@
-package hello.dao;
+package dao;
 
-import hello.model.Fortune;
+import model.Fortune;
 
 import java.util.List;
 
@@ -9,21 +9,21 @@ import javax.persistence.Query;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.persist.Transactional;
+import com.google.inject.Singleton;
 
+@Singleton
 public class FortuneDao {
 
     @Inject
     Provider<EntityManager> entitiyManagerProvider;
 
-    @Transactional
     public List<Fortune> getAll() {
-	EntityManager entityManager = entitiyManagerProvider.get();
+        EntityManager entityManager = entitiyManagerProvider.get();
 
-	Query q = entityManager.createQuery("SELECT x FROM Fortune x");
-	List<Fortune> fortunes = q.getResultList();
+        Query q = entityManager.createQuery("SELECT x FROM Fortune x");
+        List<Fortune> fortunes = q.getResultList();
 
-	return fortunes;
+        return fortunes;
     }
 
 }

+ 71 - 0
ninja-standalone/src/main/java/dao/SetupDao.java

@@ -0,0 +1,71 @@
+package dao;
+
+import model.Fortune;
+
+import javax.persistence.EntityManager;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import java.util.List;
+import javax.persistence.Query;
+import model.World;
+
+/**
+ * This class is just for testing. Has nothing to do with the TechEmpower test
+ * itself...
+ *
+ * @author ra
+ */
+@Singleton
+public class SetupDao {
+
+    @Inject
+    Provider<EntityManager> entitiyManagerProvider;
+
+    @Transactional
+    public void deleteAllData() {
+
+        entitiyManagerProvider.get().createQuery("DELETE FROM World");
+        entitiyManagerProvider.get().createQuery("DELETE FROM Fortune");
+
+    }
+
+    @Transactional
+    public void generateWorldsForTest() {
+
+        for (int i = 0; i < 10000; i++) {
+
+            World world = new World();
+            world.randomNumber = i; // not really a random number. But we can test with that...
+            entitiyManagerProvider.get().persist(world);
+
+        }
+
+    }
+
+    @Transactional
+    public void generateFortunesForTest() {
+
+        {
+
+            Fortune fortune = new Fortune();
+            // dummy message => just to make sure utf-8 works.
+            fortune.message = "レームワークのベンチマーク";
+            entitiyManagerProvider.get().persist(fortune);
+
+        }
+
+        {
+
+            Fortune fortune = new Fortune();
+            // dummy message => just to make sure utf-8 works.
+            fortune.message = "<script>I want to be escaped</script>";
+            entitiyManagerProvider.get().persist(fortune);
+
+        }
+
+    }
+
+}

+ 26 - 0
ninja-standalone/src/main/java/dao/WorldDao.java

@@ -0,0 +1,26 @@
+package dao;
+
+import model.World;
+
+import javax.persistence.EntityManager;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class WorldDao {
+
+    @Inject
+    Provider<EntityManager> entitiyManagerProvider;
+
+    public World get(int id) {
+        EntityManager entityManager = entitiyManagerProvider.get();
+        return entityManager.find(World.class, id);
+    }
+
+    public void put(World world) {
+        EntityManager entityManager = entitiyManagerProvider.get();
+        entityManager.persist(world);
+    }
+}

+ 0 - 0
ninja/src/main/resources/ehcache.xml → ninja-standalone/src/main/java/ehcache.xml


+ 0 - 50
ninja-standalone/src/main/java/hello/controllers/HelloDbController.java

@@ -1,50 +0,0 @@
-package hello.controllers;
-
-import hello.dao.WorldDao;
-import hello.model.World;
-
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-
-import ninja.Result;
-import ninja.Results;
-import ninja.params.PathParam;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class HelloDbController {
-
-    private static final int DB_ROWS = 10000;
-    private final Random random = ThreadLocalRandom.current();
-
-    @Inject
-    WorldDao worldDao;
-
-    public Result singleGet() {
-	return Results.json().render(getRandomWorld());
-    }
-
-    public Result multiGet(@PathParam("queries") Integer queries) {
-	if (queries == null || queries < 1) {
-	    queries = 1;
-	}
-	if (queries > 500) {
-	    queries = 500;
-	}
-
-	final World[] worlds = new World[queries];
-
-	for (int i = 0; i < queries; i++) {
-	    worlds[i] = getRandomWorld();
-	}
-
-	return Results.json().render(worlds);
-    }
-
-    private World getRandomWorld() {
-	return worldDao.get(random.nextInt(DB_ROWS) + 1);
-    }
-
-}

+ 0 - 28
ninja-standalone/src/main/java/hello/controllers/HelloFortuneController.java

@@ -1,28 +0,0 @@
-package hello.controllers;
-
-import hello.dao.FortuneDao;
-import hello.model.Fortune;
-
-import java.util.Collections;
-import java.util.List;
-
-import ninja.Result;
-import ninja.Results;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class HelloFortuneController {
-
-    @Inject
-    FortuneDao fortuneDao;
-
-    public Result index() {
-	List<Fortune> fortunes = fortuneDao.getAll();
-	fortunes.add(new Fortune(0, "Additional fortune added at request time."));
-	Collections.sort(fortunes);
-
-	return Results.html().render("fortunes", fortunes);
-    }
-}

+ 0 - 21
ninja-standalone/src/main/java/hello/dao/WorldDao.java

@@ -1,21 +0,0 @@
-package hello.dao;
-
-import hello.model.World;
-
-import javax.persistence.EntityManager;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.persist.Transactional;
-
-public class WorldDao {
-
-    @Inject
-    Provider<EntityManager> entitiyManagerProvider;
-
-    @Transactional
-    public World get(int id) {
-	EntityManager entityManager = entitiyManagerProvider.get();
-	return entityManager.find(World.class, id);
-    }
-}

+ 0 - 20
ninja-standalone/src/main/java/hello/views/HelloFortuneController/index.ftl.html

@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Fortunes</title>
-</head>
-<body>
-	<table>
-		<tr>
-			<th>id</th>
-			<th>message</th>
-		</tr>
-		<#list fortunes as fortune>
-		<tr>
-			<td>${fortune.id}</td>
-			<td>${fortune.message?html}</td>
-		</tr>
-		</#list>
-	</table>
-</body>
-</html>

+ 0 - 0
ninja/src/main/resources/logback.xml → ninja-standalone/src/main/java/logback.xml


+ 7 - 6
ninja/src/main/java/hello/model/Fortune.java → ninja-standalone/src/main/java/model/Fortune.java

@@ -1,4 +1,4 @@
-package hello.model;
+package model;
 
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -7,6 +7,7 @@ import javax.persistence.Id;
 
 @Entity
 public class Fortune implements Comparable<Fortune> {
+
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     public int id;
@@ -17,20 +18,20 @@ public class Fortune implements Comparable<Fortune> {
     }
 
     public Fortune(int id, String message) {
-	this.id = id;
-	this.message = message;
+        this.id = id;
+        this.message = message;
     }
 
     public int getId() {
-	return this.id;
+        return this.id;
     }
 
     public String getMessage() {
-	return this.message;
+        return this.message;
     }
 
     @Override
     public int compareTo(Fortune other) {
-	return message.compareTo(other.message);
+        return message.compareTo(other.message);
     }
 }

+ 2 - 1
ninja/src/main/java/hello/model/World.java → ninja-standalone/src/main/java/model/World.java

@@ -1,4 +1,4 @@
-package hello.model;
+package model;
 
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -7,6 +7,7 @@ import javax.persistence.Id;
 
 @Entity
 public class World {
+
     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     public int id;

+ 20 - 0
ninja-standalone/src/main/java/views/HelloFortuneController/index.ftl.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <table>
+            <tr>
+                <th>id</th>
+                <th>message</th>
+            </tr>
+            <#list fortunes as fortune>
+            <tr>
+                <td>${fortune.id}</td>
+                <td>${fortune.message}</td>
+            </tr>
+            </#list>
+        </table>
+    </body>
+</html>

+ 26 - 13
ninja-standalone/src/main/resources/META-INF/persistence.xml

@@ -4,6 +4,32 @@
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
 	version="2.0">
+    
+        
+        <!-- Database for tests and local dev mode... -->
+        <persistence-unit name="h2" transaction-type="RESOURCE_LOCAL">
+            <provider>org.hibernate.ejb.HibernatePersistence</provider>
+            <properties>
+                <property name="javax.persistence.provider" value="org.hibernate.ejb.HibernatePersistence" />
+                <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
+                <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
+                <!-- you may want to enable the ddl if you do not use migrations. -->
+                <property name="hibernate.hbm2ddl.auto" value="create" />
+                <property name="hibernate.show_sql" value="false" />
+                <property name="hibernate.format_sql" value="false" />
+
+                <!-- Connection Pooling settings -->
+                <property name="hibernate.connection.provider_class"
+                          value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
+
+                <property name="hibernate.c3p0.max_size" value="100" />
+                <property name="hibernate.c3p0.min_size" value="0" />
+                <property name="hibernate.c3p0.acquire_increment" value="1" />
+                <property name="hibernate.c3p0.idle_test_period" value="300" />
+                <property name="hibernate.c3p0.max_statements" value="0" />
+                <property name="hibernate.c3p0.timeout" value="100" />     
+            </properties>
+        </persistence-unit>
 
 	<!-- Direct mysql -->
 	<persistence-unit name="mysql" transaction-type="RESOURCE_LOCAL">
@@ -29,17 +55,4 @@
 		</properties>
 	</persistence-unit>
 
-	<!-- Resin datasource -->
-	<persistence-unit name="resin" transaction-type="RESOURCE_LOCAL">
-		<provider>org.hibernate.ejb.HibernatePersistence</provider>
-		<jta-data-source>java:comp/env/jdbc/hello_world</jta-data-source>
-
-		<properties>
-			<property name="hibernate.connection.datasource" value="java:comp/env/jdbc/hello_world" />
-			<property name="hibernate.transaction.factory_class"
-				value="org.hibernate.transaction.JTATransactionFactory" />
-			<property name="hibernate.transaction.manager_lookup_class"
-				value="org.hibernate.transaction.ResinTransactionManagerLookup" />
-		</properties>
-	</persistence-unit>
 </persistence>

+ 92 - 0
ninja-standalone/src/test/java/controllers/HelloDbControllerTest.java

@@ -0,0 +1,92 @@
+package controllers;
+
+import dao.SetupDao;
+import model.World;
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+public class HelloDbControllerTest extends NinjaDocTester {
+            
+    String URL_DB = "/db";
+    String URL_QUERIES = "/queries";
+    String URL_UPDATE = "/update";
+    
+    @Before
+    public void setupClass() {
+        getInjector().getInstance(SetupDao.class).generateWorldsForTest();
+    }
+    
+    @Test
+    public void testSingleGet() {
+        
+        Response response = makeRequest(
+                Request
+                        .GET()
+                        .url(testServerUrl().path(URL_DB))
+                        .contentTypeApplicationJson());
+        
+        // Just make sure that we get back a World Json.
+        assertThat(response.payloadAs(World.class), notNullValue());      
+                
+    }
+    
+    @Test
+    public void multipleQueries() {
+        
+        assertThatMutipleGetWorksFor(1);
+        assertThatMutipleGetWorksFor(5);
+        assertThatMutipleGetWorksFor(10);
+        assertThatMutipleGetWorksFor(15);
+        assertThatMutipleGetWorksFor(20);
+                
+    }
+    
+    private void assertThatMutipleGetWorksFor(int numberOfQueries) {
+        Response response = makeRequest(
+            Request
+                .GET()
+                .url(
+                    testServerUrl()
+                    .path(URL_QUERIES)
+                    .addQueryParameter("queries", numberOfQueries + ""))
+                .contentTypeApplicationJson());
+        
+        // Just make sure that we get back an array
+        assertThat(response.payloadAs(World[].class).length, is(numberOfQueries)); 
+    }
+    
+    @Test
+    public void testUpdates() {
+        
+        assertThatUpdateWorks(1);
+        assertThatUpdateWorks(5);
+        assertThatUpdateWorks(10);
+        assertThatUpdateWorks(15);
+        assertThatUpdateWorks(20);
+                
+    }
+    
+    private void assertThatUpdateWorks(int numberOfQueries) {
+        
+        Response response = makeRequest(
+            Request.GET()
+                .url(
+                    testServerUrl()
+                    .path(URL_UPDATE)
+                    .addQueryParameter("queries", numberOfQueries + ""))
+                .contentTypeApplicationJson());
+        
+        assertThat(response.payloadAs(World[].class).length, is(numberOfQueries)); 
+        
+    }
+
+    
+    
+}

+ 37 - 0
ninja-standalone/src/test/java/controllers/HelloFortuneControllerTest.java

@@ -0,0 +1,37 @@
+package controllers;
+
+import dao.SetupDao;
+import model.Fortune;
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class HelloFortuneControllerTest extends NinjaDocTester {
+
+    String URL_FORTUNES = "/fortunes";
+    
+    @Test
+    public void testSomeMethod() {
+        
+        getInjector().getInstance(SetupDao.class).generateFortunesForTest();
+
+        Response response 
+                = makeRequest(Request.GET().url(testServerUrl().path(URL_FORTUNES)));
+        
+        System.out.println(" " + response.payload);
+        
+        // make sure escaping works
+        assertTrue(response.payload.contains("&lt;script&gt;I want to be escaped&lt;/script&gt;"));
+
+        // make sure utf-8 works
+        assertTrue(response.payload.contains("レームワークのベンチマーク<"));
+        
+        // make sure new Fortune has been added to response
+        assertTrue(response.payload.contains("Additional fortune added at request time."));
+
+        
+    }
+    
+}

+ 48 - 0
ninja-standalone/src/test/java/controllers/HelloJsonControllerTest.java

@@ -0,0 +1,48 @@
+package controllers;
+
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+public class HelloJsonControllerTest extends NinjaDocTester {
+    
+    String URL_JSON = "/json";
+
+    @Test
+    public void testHelloJsonController() {
+        
+        Response response = makeRequest(
+            Request
+                .GET()
+                .url(testServerUrl().path(URL_JSON))
+                .contentTypeApplicationJson());
+        
+        assertThat(
+            response.payloadAs(Message.class).message, 
+            is("Hello, world"));
+        
+    }
+    
+    /**
+     * Duplicated from HelloJsonController.
+     * 
+     * Stuff in HelloJsonController is final, but to deserialize the message we
+     * need an empty constructor...
+     */
+    public final static class Message {
+
+	public String message;
+        
+	public Message() {}
+
+	public Message(String message) {
+	    this.message = message;
+	}
+    }
+    
+}

+ 29 - 0
ninja-standalone/src/test/java/controllers/HelloPlaintextControllerTest.java

@@ -0,0 +1,29 @@
+package controllers;
+
+import ninja.NinjaDocTester;
+import org.doctester.testbrowser.Request;
+import org.doctester.testbrowser.Response;
+import org.hamcrest.CoreMatchers;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class HelloPlaintextControllerTest extends NinjaDocTester {
+    
+    String URL_PLAINTEXT = "/plaintext";
+    
+    @Test
+    public void helloPlaintextControllerTest() {
+        
+        Response response = makeRequest(
+            Request.GET().url(testServerUrl().path(URL_PLAINTEXT)));
+        
+        assertThat(response.payload, CoreMatchers.is("Hello, world!"));
+        assertThat(
+            response.headers.get("Content-Type"), 
+            is("text/plain; charset=UTF-8"));
+        
+   
+    }
+    
+}

+ 0 - 157
ninja/pom.xml

@@ -1,157 +0,0 @@
-<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>helo.world</groupId>
-	<artifactId>hello-ninja</artifactId>
-	<version>0.0.1-SNAPSHOT</version>
-	<name>Ninja Framework Test Project</name>
-	<description>Nnja test for the TechEmpower/FrameworkBenchmarks project</description>
-
-	<properties>
-		<java-version>1.7</java-version>
-		<ninja.version>2.1.0</ninja.version>
-		<mysql.version>5.1.26</mysql.version>
-		<jetty.version>9.0.5.v20130815</jetty.version>
-	</properties>
-
-	<dependencies>
-		<dependency>
-			<groupId>org.ninjaframework</groupId>
-			<artifactId>ninja-servlet</artifactId>
-			<version>${ninja.version}</version>
-		</dependency>
-
-		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>javax.servlet-api</artifactId>
-			<version>3.0.1</version>
-			<scope>provided</scope>
-		</dependency>
-
-		<dependency>
-			<groupId>org.ninjaframework</groupId>
-			<artifactId>ninja-test-utilities</artifactId>
-			<version>${ninja.version}</version>
-			<scope>test</scope>
-		</dependency>
-
-		<dependency>
-			<groupId>mysql</groupId>
-			<artifactId>mysql-connector-java</artifactId>
-			<version>${mysql.version}</version>
-		</dependency>
-	</dependencies>
-
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-compiler-plugin</artifactId>
-				<version>3.1</version>
-				<configuration>
-					<source>${java-version}</source>
-					<target>${java-version}</target>
-				</configuration>
-			</plugin>
-			
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-war-plugin</artifactId>
-                <configuration>
-                    <warName>ninja</warName>
-                </configuration>
-            </plugin>
-
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-enforcer-plugin</artifactId>
-				<version>1.0</version>
-				<executions>
-					<execution>
-						<id>enforce-banned-dependencies</id>
-						<goals>
-							<goal>enforce</goal>
-						</goals>
-						<configuration>
-							<rules>
-								<bannedDependencies>
-									<excludes>
-										<exclude>commons-logging</exclude>
-									</excludes>
-								</bannedDependencies>
-							</rules>
-							<fail>true</fail>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
-
-			<plugin>
-				<groupId>org.eclipse.jetty</groupId>
-				<artifactId>jetty-maven-plugin</artifactId>
-				<version>${jetty.version}</version>
-				<configuration>
-					<contextPath>/</contextPath>
-					<stopKey>stop</stopKey>
-					<stopPort>8889</stopPort>
-					<scanIntervalSeconds>1</scanIntervalSeconds>
-					<reload>automatic</reload>
-					<scanTargetPatterns>
-						<scanTargetPattern>
-							<directory>target/classes</directory>
-							<includes>
-								<include>**/*</include>
-							</includes>
-							<excludes>
-								<exclude>**/*.ftl.html</exclude>
-								<exclude>assets/**</exclude>
-							</excludes>
-						</scanTargetPattern>
-					</scanTargetPatterns>
-				</configuration>
-			</plugin>
-
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-deploy-plugin</artifactId>
-				<version>2.7</version>
-				<configuration>
-					<skip>true</skip>
-				</configuration>
-			</plugin>
-
-			<plugin>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<version>2.4</version>
-				<configuration>
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<mainClass>ninja.standalone.NinjaJetty</mainClass>
-						</manifest>
-					</archive>
-				</configuration>
-			</plugin>
-		</plugins>
-
-		<resources>
-			<resource>
-				<directory>src/main/java</directory>
-				<includes>
-					<include>**/*</include>
-				</includes>
-				<excludes>
-					<exclude>**/*.java</exclude>
-				</excludes>
-			</resource>
-			<resource>
-				<directory>src/main/resources</directory>
-				<includes>
-					<include>**/*</include>
-				</includes>
-			</resource>
-		</resources>
-	</build>
-</project>

+ 0 - 26
ninja/src/main/java/conf/Routes.java

@@ -1,26 +0,0 @@
-package conf;
-
-import hello.controllers.HelloDbController;
-import hello.controllers.HelloFortuneController;
-import hello.controllers.HelloJsonController;
-import hello.controllers.HelloPlaintextController;
-import ninja.Router;
-import ninja.application.ApplicationRoutes;
-
-public class Routes implements ApplicationRoutes {
-
-    @Override
-    public void init(Router router) {
-
-	router.GET().route("/").with(HelloPlaintextController.class, "index");
-	router.GET().route("/plaintext")
-		.with(HelloPlaintextController.class, "index");
-	router.GET().route("/json").with(HelloJsonController.class, "index");
-	router.GET().route("/queries/{queries}")
-		.with(HelloDbController.class, "multiGet");
-	router.GET().route("/db").with(HelloDbController.class, "singleGet");
-	router.GET().route("/fortunes")
-		.with(HelloFortuneController.class, "index");
-
-    }
-}

+ 0 - 50
ninja/src/main/java/hello/controllers/HelloDbController.java

@@ -1,50 +0,0 @@
-package hello.controllers;
-
-import hello.dao.WorldDao;
-import hello.model.World;
-
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-
-import ninja.Result;
-import ninja.Results;
-import ninja.params.PathParam;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class HelloDbController {
-
-    private static final int DB_ROWS = 10000;
-    private final Random random = ThreadLocalRandom.current();
-
-    @Inject
-    WorldDao worldDao;
-
-    public Result singleGet() {
-	return Results.json().render(getRandomWorld());
-    }
-
-    public Result multiGet(@PathParam("queries") Integer queries) {
-	if (queries == null || queries < 1) {
-	    queries = 1;
-	}
-	if (queries > 500) {
-	    queries = 500;
-	}
-
-	final World[] worlds = new World[queries];
-
-	for (int i = 0; i < queries; i++) {
-	    worlds[i] = getRandomWorld();
-	}
-
-	return Results.json().render(worlds);
-    }
-
-    private World getRandomWorld() {
-	return worldDao.get(random.nextInt(DB_ROWS) + 1);
-    }
-
-}

+ 0 - 28
ninja/src/main/java/hello/controllers/HelloFortuneController.java

@@ -1,28 +0,0 @@
-package hello.controllers;
-
-import hello.dao.FortuneDao;
-import hello.model.Fortune;
-
-import java.util.Collections;
-import java.util.List;
-
-import ninja.Result;
-import ninja.Results;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class HelloFortuneController {
-
-    @Inject
-    FortuneDao fortuneDao;
-
-    public Result index() {
-	List<Fortune> fortunes = fortuneDao.getAll();
-	fortunes.add(new Fortune(0, "Additional fortune added at request time."));
-	Collections.sort(fortunes);
-
-	return Results.html().render("fortunes", fortunes);
-    }
-}

+ 0 - 21
ninja/src/main/java/hello/dao/WorldDao.java

@@ -1,21 +0,0 @@
-package hello.dao;
-
-import hello.model.World;
-
-import javax.persistence.EntityManager;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.persist.Transactional;
-
-public class WorldDao {
-
-    @Inject
-    Provider<EntityManager> entitiyManagerProvider;
-
-    @Transactional
-    public World get(int id) {
-	EntityManager entityManager = entitiyManagerProvider.get();
-	return entityManager.find(World.class, id);
-    }
-}

+ 0 - 20
ninja/src/main/java/hello/views/HelloFortuneController/index.ftl.html

@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Fortunes</title>
-</head>
-<body>
-	<table>
-		<tr>
-			<th>id</th>
-			<th>message</th>
-		</tr>
-		<#list fortunes as fortune>
-		<tr>
-			<td>${fortune.id}</td>
-			<td>${fortune.message}</td>
-		</tr>
-		</#list>
-	</table>
-</body>
-</html>

+ 0 - 45
ninja/src/main/resources/META-INF/persistence.xml

@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<persistence xmlns="http://java.sun.com/xml/ns/persistence"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
-	version="2.0">
-
-	<!-- Direct mysql -->
-	<persistence-unit name="mysql" transaction-type="RESOURCE_LOCAL">
-		<provider>org.hibernate.ejb.HibernatePersistence</provider>
-
-		<properties>
-			<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
-			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
-
-			<property name="hibernate.show_sql" value="false" />
-			<property name="hibernate.format_sql" value="false" />
-
-			<!-- Connection Pooling settings -->
-			<property name="hibernate.connection.provider_class"
-				value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
-
-			<property name="hibernate.c3p0.max_size" value="100" />
-			<property name="hibernate.c3p0.min_size" value="0" />
-			<property name="hibernate.c3p0.acquire_increment" value="1" />
-			<property name="hibernate.c3p0.idle_test_period" value="300" />
-			<property name="hibernate.c3p0.max_statements" value="0" />
-			<property name="hibernate.c3p0.timeout" value="100" />
-		</properties>
-	</persistence-unit>
-
-	<!-- Resin datasource -->
-	<persistence-unit name="resin" transaction-type="RESOURCE_LOCAL">
-		<provider>org.hibernate.ejb.HibernatePersistence</provider>
-		<jta-data-source>java:comp/env/jdbc/hello_world</jta-data-source>
-
-		<properties>
-			<property name="hibernate.connection.datasource" value="java:comp/env/jdbc/hello_world" />
-			<property name="hibernate.transaction.factory_class"
-				value="org.hibernate.transaction.JTATransactionFactory" />
-			<property name="hibernate.transaction.manager_lookup_class"
-				value="org.hibernate.transaction.ResinTransactionManagerLookup" />
-		</properties>
-	</persistence-unit>
-</persistence>

+ 0 - 13
ninja/src/main/webapp/WEB-INF/resin-web.xml

@@ -1,13 +0,0 @@
-<web-app xmlns="http://caucho.com/ns/resin">
-
-<database jndi-name='jdbc/hello_world'>
-  <driver>
-    <type>com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource</type>
-    <url>jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&amp;elideSetAutoCommits=true&amp;useLocalSessionState=true&amp;cachePrepStmts=true&amp;cacheCallableStmts=true&amp;alwaysSendSetIsolation=false&amp;prepStmtCacheSize=4096&amp;cacheServerConfiguration=true&amp;prepStmtCacheSqlLimit=2048&amp;zeroDateTimeBehavior=convertToNull&amp;traceProtocol=false&amp;useUnbufferedInput=false&amp;useReadAheadInput=false&amp;maintainTimeStats=false&amp;useServerPrepStmts&amp;cacheRSMetadata=true</url>
-    <user>benchmarkdbuser</user>
-    <password>benchmarkdbpass</password>
-    <useUnicode/>
-  </driver>
-</database>
-
-</web-app>