Browse Source

Revert "Removed ninja-resin - makes too much trouble - and"

This reverts commit d4097ed583eff2c898bd5b2364c29e5d462f90e8.
Raphael A. Bauer 11 years ago
parent
commit
f49ea9df4b
33 changed files with 1150 additions and 0 deletions
  1. 20 0
      ninja-resin/.gitignore
  2. 44 0
      ninja-resin/README.md
  3. 0 0
      ninja-resin/__init__.py
  4. 2 0
      ninja-resin/bash_profile.sh
  5. 28 0
      ninja-resin/benchmark_config
  6. 16 0
      ninja-resin/changelog.md
  7. 3 0
      ninja-resin/install.sh
  8. 166 0
      ninja-resin/pom.xml
  9. 32 0
      ninja-resin/setup.py
  10. 35 0
      ninja-resin/source_code
  11. 35 0
      ninja-resin/src/main/java/conf/Routes.java
  12. 49 0
      ninja-resin/src/main/java/conf/application.conf
  13. 17 0
      ninja-resin/src/main/java/conf/messages.properties
  14. 78 0
      ninja-resin/src/main/java/controllers/HelloDbController.java
  15. 30 0
      ninja-resin/src/main/java/controllers/HelloFortuneController.java
  16. 23 0
      ninja-resin/src/main/java/controllers/HelloJsonController.java
  17. 13 0
      ninja-resin/src/main/java/controllers/HelloPlaintextController.java
  18. 35 0
      ninja-resin/src/main/java/controllers/SetupController.java
  19. 29 0
      ninja-resin/src/main/java/dao/FortuneDao.java
  20. 71 0
      ninja-resin/src/main/java/dao/SetupDao.java
  21. 26 0
      ninja-resin/src/main/java/dao/WorldDao.java
  22. 15 0
      ninja-resin/src/main/java/ehcache.xml
  23. 14 0
      ninja-resin/src/main/java/logback.xml
  24. 37 0
      ninja-resin/src/main/java/model/Fortune.java
  25. 15 0
      ninja-resin/src/main/java/model/World.java
  26. 20 0
      ninja-resin/src/main/java/views/HelloFortuneController/index.ftl.html
  27. 46 0
      ninja-resin/src/main/resources/META-INF/persistence.xml
  28. 13 0
      ninja-resin/src/main/webapp/WEB-INF/resin-web.xml
  29. 32 0
      ninja-resin/src/main/webapp/WEB-INF/web.xml
  30. 92 0
      ninja-resin/src/test/java/controllers/HelloDbControllerTest.java
  31. 37 0
      ninja-resin/src/test/java/controllers/HelloFortuneControllerTest.java
  32. 48 0
      ninja-resin/src/test/java/controllers/HelloJsonControllerTest.java
  33. 29 0
      ninja-resin/src/test/java/controllers/HelloPlaintextControllerTest.java

+ 20 - 0
ninja-resin/.gitignore

@@ -0,0 +1,20 @@
+.DS_Store
+*.pyc
+installs/
+*.log
+*.lock
+node_modules/
+*.war
+target/
+*.out
+*.class
+mods/
+/.settings
+/.buildpath
+/.project
+*.iml
+.idea/
+.hsenv/
+azure.err
+*~
+/.classpath

+ 44 - 0
ninja-resin/README.md

@@ -0,0 +1,44 @@
+# Ninja Framework Benchmarking Test
+
+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.
+
+## Contributors and thanks
+
+ * The whole TE team for making this possible. Thanks for your time and patience!
+ * kpacha - Kudos to kpacha for creating the initial TE benchmark suite for Ninja!
+ * raphael - Updating and maintenance of Ninja TE benchmarks
+ * martin-g - Many thanks for fixing the issue with resin persistence.xml. Awesome! 
+
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost:8080/ninja/json
+
+### Single Query Test
+
+http://localhost:8080/ninja/db
+
+### Multiple Queries Test
+
+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-resin/__init__.py


+ 2 - 0
ninja-resin/bash_profile.sh

@@ -0,0 +1,2 @@
+export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-amd64
+export RESIN_HOME=${IROOT}/resin-4.0.36

+ 28 - 0
ninja-resin/benchmark_config

@@ -0,0 +1,28 @@
+{
+  "framework": "ninja-resin",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/ninja/json",
+      "db_url": "/ninja/db",
+      "query_url": "/ninja/queries?queries=",
+      "fortune_url": "/ninja/fortunes",
+      "update_url": "/ninja/update?queries=",
+      "plaintext_url": "/ninja/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "ninja",
+      "language": "Java",
+      "orm": "Full",
+      "platform": "Servlet",
+      "webserver": "Resin",
+      "os": "Linux",
+      "database_os": "Linux",
+      "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.

+ 3 - 0
ninja-resin/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fw_depends java resin maven

+ 166 - 0
ninja-resin/pom.xml

@@ -0,0 +1,166 @@
+<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>
+    <packaging>war</packaging>
+    <description>Ninja test for the TechEmpower/FrameworkBenchmarks project</description>
+
+    <properties>
+        <java.version>1.7</java.version>
+        <ninja.version>3.3.1</ninja.version>
+        <mysql.version>5.1.26</mysql.version>
+        <jetty.version>9.2.1.v20140609</jetty.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.ninjaframework</groupId>
+            <artifactId>ninja-standalone</artifactId>
+            <version>${ninja.version}</version>
+        </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>
+                </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>

+ 32 - 0
ninja-resin/setup.py

@@ -0,0 +1,32 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args, logfile, errfile):
+  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-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-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-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
+def stop(logfile, errfile):
+  try:
+    if os.name == 'nt':
+      subprocess.check_call('"%RESIN_HOME%\\bin\\stop.bat"', shell=True, stderr=errfile, stdout=logfile)
+    else:
+      subprocess.check_call("$RESIN_HOME/bin/resinctl shutdown", shell=True, stderr=errfile, stdout=logfile)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 35 - 0
ninja-resin/source_code

@@ -0,0 +1,35 @@
+./ninja/src/
+./ninja/src/main/
+./ninja/src/main/java/
+./ninja/src/main/java/conf
+./ninja/src/main/java/conf/Routes.java
+./ninja/src/main/java/conf/application.conf
+./ninja/src/main/java/conf/messages.properties
+./ninja/src/main/java/hello/
+./ninja/src/main/java/hello/controllers/
+./ninja/src/main/java/hello/controllers/HelloDbController.java
+./ninja/src/main/java/hello/controllers/HelloFortuneController.java
+./ninja/src/main/java/hello/controllers/HelloJsonController.java
+./ninja/src/main/java/hello/controllers/HelloPlaintextController.java
+./ninja/src/main/java/hello/dao/
+./ninja/src/main/java/hello/dao/FortuneDao.java
+./ninja/src/main/java/hello/dao/WorldDao.java
+./ninja/src/main/java/hello/model/
+./ninja/src/main/java/hello/model/Fortune.java
+./ninja/src/main/java/hello/model/World.java
+./ninja/src/main/java/hello/views/
+./ninja/src/main/java/hello/views/HelloFortuneController/
+./ninja/src/main/java/hello/views/HelloFortuneController/index.ftl.html
+./ninja/src/main/resources/
+./ninja/src/main/resources/META-INF/
+./ninja/src/main/resources/META-INF/persistence.xml
+./ninja/src/main/resources/conf/
+./ninja/src/main/resources/conf/application.conf
+./ninja/src/main/resources/conf/messages.properties
+./ninja/src/main/resources/ehcache.xml
+./ninja/src/main/resources/logback.xml
+./ninja/src/main/webapp/
+./ninja/src/main/webapp/WEB-INF/
+./ninja/src/main/webapp/WEB-INF/resin-web.xml
+./ninja/src/main/webapp/WEB-INF/web.xml
+

+ 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");
+        }
+
+    }
+}

+ 49 - 0
ninja-resin/src/main/java/conf/application.conf

@@ -0,0 +1,49 @@
+##############################################################################
+# The main properties file to configure your application
+#
+# Properties can be prefixed by "%".
+# "%"" matches a mode you can set as system property. For instance when you
+# are using maven you can do: mvn -Dmode=test jetty:run
+#
+# Using that the following property:
+# %test.myproperty=test property
+# would overwrite the property
+# myproperty=my property
+#
+# You can define as many environments as you want. Simply set them in the mode.
+##############################################################################
+application.name=ninja test application
+
+application.cookie.prefix=NINJA
+
+#ISO Language Code, optionally followed by a valid ISO Country Code. 
+application.languages=en
+
+application.session.expire_time_in_seconds=3600
+application.session.send_only_if_changed=true
+application.session.transferred_over_https_only=false
+
+##############################################################################
+# Configure JPA
+# simply tell Ninja which persistence unit to use.
+# The persistence units are defined at META-INF/persistence.xml
+##############################################################################
+ninja.migration.run=false
+
+%prod.ninja.jpa.persistence_unit_name = resin
+
+## 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
+%test.db.connection.username=ra
+%test.db.connection.password=
+
+application.secret = b9z4AQO0huDRrJXFVjNiNXmSVqPSbcqjEiNjdPVBApb8n9GnxVjWBr9jp8tRfe73

+ 17 - 0
ninja-resin/src/main/java/conf/messages.properties

@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2012 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This file is utf-8

+ 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);
+    }
+}

+ 23 - 0
ninja-resin/src/main/java/controllers/HelloJsonController.java

@@ -0,0 +1,23 @@
+package controllers;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Singleton;
+
+@Singleton
+public class HelloJsonController {
+
+    public Result index() {
+	return Results.json().render(new Message("Hello, World!"));
+    }
+
+    public final static class Message {
+
+	public final String message;
+
+	public Message(String message) {
+	    this.message = message;
+	}
+    }
+}

+ 13 - 0
ninja-resin/src/main/java/controllers/HelloPlaintextController.java

@@ -0,0 +1,13 @@
+package controllers;
+
+import ninja.Result;
+import ninja.Results;
+
+import com.google.inject.Singleton;
+
+@Singleton
+public class HelloPlaintextController {
+    public Result index() {
+	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");
+        
+    }
+    
+   
+
+}

+ 29 - 0
ninja-resin/src/main/java/dao/FortuneDao.java

@@ -0,0 +1,29 @@
+package dao;
+
+import model.Fortune;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class FortuneDao {
+
+    @Inject
+    Provider<EntityManager> entitiyManagerProvider;
+
+    public List<Fortune> getAll() {
+        EntityManager entityManager = entitiyManagerProvider.get();
+
+        Query q = entityManager.createQuery("SELECT x FROM Fortune x");
+        List<Fortune> fortunes = q.getResultList();
+
+        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);
+    }
+}

+ 15 - 0
ninja-resin/src/main/java/ehcache.xml

@@ -0,0 +1,15 @@
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd" updateCheck="false">
+
+    <defaultCache
+            maxElementsInMemory="10000"
+            eternal="false"
+            timeToIdleSeconds="120"
+            timeToLiveSeconds="120"
+            overflowToDisk="false"
+            maxElementsOnDisk="10000000"
+            diskPersistent="false"
+            diskExpiryThreadIntervalSeconds="120"
+            memoryStoreEvictionPolicy="LRU"
+    /> 
+    
+</ehcache>

+ 14 - 0
ninja-resin/src/main/java/logback.xml

@@ -0,0 +1,14 @@
+<configuration>
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type
+         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>

+ 37 - 0
ninja-resin/src/main/java/model/Fortune.java

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

+ 15 - 0
ninja-resin/src/main/java/model/World.java

@@ -0,0 +1,15 @@
+package model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class World {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    public int id;
+    public int randomNumber;
+}

+ 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>

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

@@ -0,0 +1,46 @@
+<?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.jpa.HibernatePersistenceProvider</provider-->
+        <jta-data-source>java:comp/env/jdbc/hello_world</jta-data-source>
+        <shared-cache-mode>NONE</shared-cache-mode>
+        <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" />
+            <property name="hibernate.jdbc.batch_size" value="100" />
+        </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.jpa.HibernatePersistenceProvider" />
+            <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>

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

@@ -0,0 +1,13 @@
+<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>

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

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (C) 2013 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true" version="3.0">
+  <display-name>ninja</display-name>
+  <listener>
+    <listener-class>ninja.servlet.NinjaServletListener</listener-class>
+  </listener>
+  <filter>
+    <filter-name>guiceFilter</filter-name>
+    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+  </filter>
+  <filter-mapping>
+    <filter-name>guiceFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+</web-app>

+ 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"));
+        
+   
+    }
+    
+}