瀏覽代碼

Added the remaining tests.
Bumped Play version to 2.3.6.
Added HikariCP benchmark config.

Donovan Muller 11 年之前
父節點
當前提交
66e1a070ed
共有 33 個文件被更改,包括 781 次插入37 次删除
  1. 27 2
      frameworks/Java/play2-java/benchmark_config
  2. 12 10
      frameworks/Java/play2-java/generate_config.py
  3. 29 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/.gitignore
  4. 40 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/README.md
  5. 151 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java
  6. 34 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/models/Fortune.java
  7. 38 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/models/World.java
  8. 21 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Headers.java
  9. 8 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Predicate.java
  10. 26 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Predicated.java
  11. 23 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/PredicatedAction.java
  12. 16 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/views/fortunes.scala.html
  13. 12 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/views/main.scala.html
  14. 17 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/build.sbt
  15. 14 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/META-INF/persistence.xml
  16. 97 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf
  17. 1 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/play.plugins
  18. 13 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/routes
  19. 1 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/build.properties
  20. 4 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt
  21. 11 0
      frameworks/Java/play2-java/play2-java-jpa-hikaricp/source_code
  22. 18 6
      frameworks/Java/play2-java/play2-java-jpa/README.md
  23. 51 10
      frameworks/Java/play2-java/play2-java-jpa/app/controllers/Application.java
  24. 34 0
      frameworks/Java/play2-java/play2-java-jpa/app/models/Fortune.java
  25. 21 6
      frameworks/Java/play2-java/play2-java-jpa/app/models/World.java
  26. 21 0
      frameworks/Java/play2-java/play2-java-jpa/app/utils/Headers.java
  27. 16 0
      frameworks/Java/play2-java/play2-java-jpa/app/views/fortunes.scala.html
  28. 12 0
      frameworks/Java/play2-java/play2-java-jpa/app/views/main.scala.html
  29. 1 1
      frameworks/Java/play2-java/play2-java-jpa/build.sbt
  30. 3 1
      frameworks/Java/play2-java/play2-java-jpa/conf/routes
  31. 1 1
      frameworks/Java/play2-java/play2-java-jpa/project/plugins.sbt
  32. 2 0
      frameworks/Java/play2-java/play2-java-jpa/source_code
  33. 6 0
      frameworks/Java/play2-java/setup_java_jpa_hikaricp.py

+ 27 - 2
frameworks/Java/play2-java/benchmark_config

@@ -56,8 +56,33 @@
         "versus": "netty", 
         "port": "9000", 
         "db_url": "/db", 
-        "query_url": "/queries?queries="
+        "query_url": "/queries?queries=", 
+        "fortune_url": "/fortunes", 
+        "update_url": "/update?queries=", 
+        "plaintext_url": "/plaintext"
+      }, 
+      "java-jpa-hikaricp": {
+        "display_name": "play2-java-jpa-hikaricp", 
+        "setup_file": "setup_java_jpa_hikaricp", 
+        "framework": "play2", 
+        "language": "Java", 
+        "orm": "Full", 
+        "os": "Linux", 
+        "database": "MySQL", 
+        "approach": "Realistic", 
+        "classification": "Fullstack", 
+        "platform": "Netty", 
+        "webserver": "None", 
+        "database_os": "Linux", 
+        "notes": "", 
+        "versus": "netty", 
+        "port": "9000", 
+        "db_url": "/db", 
+        "query_url": "/queries?queries=", 
+        "fortune_url": "/fortunes", 
+        "update_url": "/update?queries=", 
+        "plaintext_url": "/plaintext"
       }
     }
   ]
-}
+}

+ 12 - 10
frameworks/Java/play2-java/generate_config.py

@@ -9,12 +9,13 @@ import collections, json, os, textwrap
 # Format is: (language, orm, (opsys, ...), (test, ...))
 # See the dir_name logic below to see the directory name for each test application.
 configurations = [
-  ('Java',  None,    ['Linux'],            ['json']),
-  ('Java',  'Ebean', ['Linux'],            ['db', 'query']),
-  ('Java',  'JPA',   ['Linux'],            ['db', 'query']),
-  ('Scala', None,    ['Linux'],            ['json']),
-  ('Scala', 'Anorm', ['Linux', 'Windows'], ['db', 'query', 'fortune', 'update']),
-  ('Scala', 'Slick', ['Linux'],            ['db', 'query', 'fortune', 'update']),
+  ('Java',  None,    			['Linux'],            ['json']),
+  ('Java',  'Ebean', 			['Linux'],            ['db', 'query']),
+  ('Java',  'JPA',   			['Linux'],            ['db', 'query', 'fortune', 'update', 'plaintext']),
+  ('Java',  'JPA HikariCP',   	['Linux'],            ['db', 'query', 'fortune', 'update', 'plaintext']),
+  ('Scala', None,    			['Linux'],            ['json']),
+  ('Scala', 'Anorm', 			['Linux', 'Windows'], ['db', 'query', 'fortune', 'update']),
+  ('Scala', 'Slick', 			['Linux'],            ['db', 'query', 'fortune', 'update']),
 ]
 
 # All play2 test applications must use the same URLs.
@@ -24,6 +25,7 @@ test_urls = {
   'query': '/queries?queries=',
   'fortune': '/fortunes',
   'update': '/update?queries=',
+  'plaintext': '/plaintext',
 }
 
 langs = {
@@ -41,8 +43,8 @@ for lang, _ in langs.iteritems():
   lang_test_configs[lang] = collections.OrderedDict()
 
 for lang, orm, opsyses, tests in configurations:
-  dir_name = 'play2-' + lang.lower() + (('-'+orm.lower()) if orm else '')
-  setup_name = 'setup_' + lang.lower() + (('_'+orm.lower()) if orm else '')
+  dir_name = 'play2-' + lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
+  setup_name = 'setup_' + lang.lower() + (('_'+orm.replace(' ', '_').lower()) if orm else '')
 
   setup_path = os.path.join(pathForLang(lang), setup_name+'.py')
   print 'Generating', setup_path
@@ -57,9 +59,9 @@ for lang, orm, opsyses, tests in configurations:
 
   for opsys in opsyses:
     if len(opsyses) == 1:
-      test_name = lang.lower() + (('-'+orm.lower()) if orm else '')
+      test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
     else:
-      test_name = lang.lower() + (('-'+orm.lower()) if orm else '') + '-'+opsys.lower()
+      test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '') + '-'+opsys.lower()
     test_config_json = collections.OrderedDict([
       ('display_name', 'play2-'+test_name),
       ('setup_file', setup_name),

+ 29 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/.gitignore

@@ -0,0 +1,29 @@
+logs
+project/project
+project/target
+target
+tmp
+.history
+dist
+
+# Ignore all dotfiles...
+.*
+# except for .gitignore
+!.gitignore
+
+# Ignore Play! working directory #
+db
+eclipse
+lib
+log
+logs
+modules
+precompiled
+project/project
+project/target
+target
+tmp
+test-result
+server.pid
+*.iml
+*.eml

+ 40 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/README.md

@@ -0,0 +1,40 @@
+#Play Benchmarking Test
+
+This is the Play portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](app/controllers/Application.java)
+
+### Data-Store/Database Mapping Test
+
+* [Database test controller](app/controllers/Application.java)
+* [Database World test model](app/models/World.java)
+* [Database Fortune test model](app/models/Fortune.java)
+
+### Plain Text Test
+
+* [Plain text test controller](app/controllers/Application.java)
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Java OpenJDK 1.7](http://openjdk.java.net/)
+* [Play 2.3.6](http://http://www.playframework.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+* http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+* http://localhost/db
+* http://localhost/queries?queries=10
+* http://localhost/fortunes
+* http://localhost/update?queries=10
+
+### Plain Text Test
+
+* http://localhost/plaintext
+

+ 151 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java

@@ -0,0 +1,151 @@
+package controllers;
+
+import akka.dispatch.ExecutionContexts;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import models.Fortune;
+import models.World;
+import play.*;
+import play.core.NamedThreadFactory;
+import play.libs.F;
+import play.libs.Json;
+import play.mvc.*;
+
+import scala.concurrent.ExecutionContext;
+import utils.Predicate;
+import utils.Predicated;
+import views.html.*;
+
+import java.util.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+public class Application extends Controller {
+
+    private static final int MAX_QUERIES_PER_REQUEST = 20;
+    private static final int TEST_DATABASE_ROWS = 10000;
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    private static final int partitionCount = Play.application().configuration().getInt("db.default.partitionCount");
+    private static final int maxConnections =
+            partitionCount * Play.application().configuration().getInt("db.default.maxConnectionsPerPartition");
+    private static final int minConnections =
+            partitionCount * Play.application().configuration().getInt("db.default.minConnectionsPerPartition");
+
+    private static final ThreadPoolExecutor tpe = new ThreadPoolExecutor(minConnections, maxConnections,
+            0L, TimeUnit.MILLISECONDS,
+            new LinkedBlockingQueue<Runnable>(),
+            new NamedThreadFactory("dbEc"));
+    private static final ExecutionContext dbEc = ExecutionContexts.fromExecutorService(tpe);
+
+    public static Result json() {
+        final ObjectNode result = OBJECT_MAPPER.createObjectNode();
+        result.put("message", "Hello World!");
+        return ok(result);
+    }
+
+    // If the thread-pool used by the database grows too large then our server
+    // is probably struggling, and we should start dropping requests. Set
+    // the max size of our queue something above the number of concurrent
+    // connections that we need to handle.
+    public static class IsDbAvailable implements Predicate {
+        @Override
+        public boolean condition() {
+            return tpe.getQueue().size() <= 1024;
+        }
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> db() {
+        return getRandomWorlds(1).map(new F.Function<List<World>, Result>() {
+            @Override
+            public Result apply(List<World> worlds) {
+                return ok(Json.toJson(worlds.get(0)));
+            }
+        });
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> queries(final String queryCountString) {
+        return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
+            @Override
+            public Result apply(List<World> worlds) {
+                return ok(Json.toJson(worlds));
+            }
+        });
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> fortunes() {
+        return F.Promise.promise(new F.Function0<Result>() {
+
+            @Override
+            public Result apply() throws Throwable {
+                List<Fortune> fortunes = Fortune.findAll();
+                fortunes.add(new Fortune("Additional fortune added at request time."));
+                Collections.sort(fortunes, new Comparator<Fortune>() {
+                    @Override
+                    public int compare(Fortune f1, Fortune f2) {
+                        return f1.message.compareTo(f2.message);
+                    }
+                });
+                return ok(views.html.fortunes.render(fortunes));
+            }
+        }, dbEc);
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> update(final String queryCountString) {
+        return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
+            @Override
+            public Result apply(List<World> worlds) throws Throwable {
+                Random random = ThreadLocalRandom.current();
+                for (World world : worlds) {
+                    world.randomNumber = (long) (random.nextInt(10000) + 1);
+                }
+
+                worlds = World.save(worlds);
+                return ok(Json.toJson(worlds));
+            }
+        });
+    }
+
+    public static Result plainText() {
+        return ok("Hello, World!");
+    }
+
+    private static int queryCount(String queryCountString) {
+        int queryCount;
+        try {
+            queryCount = Integer.parseInt(queryCountString, 10);
+        } catch (NumberFormatException e) {
+            queryCount = 1;
+        }
+        if (queryCount < 1) {
+            queryCount = 1;
+        } else if (queryCount > 500) {
+            queryCount = 500;
+        }
+
+        return queryCount;
+    }
+
+    private static F.Promise<List<World>> getRandomWorlds(final int n) {
+        return F.Promise.promise(new F.Function0<List<World>>() {
+            @Override
+            public List<World> apply() throws Throwable {
+                Random random = ThreadLocalRandom.current();
+                List<World> worlds = new ArrayList<World>(n);
+                for (int i = 0; i < n; ++i) {
+                    long randomId = random.nextInt(TEST_DATABASE_ROWS) + 1;
+                    World world = World.findById(randomId);
+                    worlds.add(world);
+                }
+                return worlds;
+            }
+        }, dbEc);
+    }
+
+}

+ 34 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/models/Fortune.java

@@ -0,0 +1,34 @@
+package models;
+
+import play.db.jpa.JPA;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.criteria.CriteriaQuery;
+import java.util.List;
+
+@Entity
+public class Fortune {
+
+    @Id
+    public Long id = 0L;
+
+    public String message;
+
+    public Fortune() {
+    }
+
+    public Fortune(String message) {
+        this.message = message;
+    }
+
+    public static List<Fortune> findAll() throws Throwable {
+        return JPA.withTransaction("default", true, new play.libs.F.Function0<List<Fortune>>() {
+            public List<Fortune> apply() {
+                CriteriaQuery<Fortune> criteria = JPA.em().getCriteriaBuilder().createQuery(Fortune.class);
+                criteria.select(criteria.from(Fortune.class));
+                return JPA.em().createQuery(criteria).getResultList();
+            }
+        });
+    }
+}

+ 38 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/models/World.java

@@ -0,0 +1,38 @@
+package models;
+
+import play.db.jpa.JPA;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.List;
+
+@Entity
+public class World {
+
+    @Id
+    public Long id;
+
+    @Column(name = "randomNumber")
+    public Long randomNumber;
+
+    public static World findById(final Long id) throws Throwable {
+        return JPA.withTransaction("default", true, new play.libs.F.Function0<World>() {
+            public World apply() {
+                return JPA.em().find(World.class, id);
+            }
+        });
+    }
+
+    public static List<World> save(final List<World> worlds) throws Throwable {
+        for (final World world : worlds) {
+            JPA.withTransaction("default", false, new play.libs.F.Function0<World>() {
+                public World apply() {
+                    return JPA.em().merge(world);
+                }
+            });
+        }
+
+        return worlds;
+    }
+}

+ 21 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Headers.java

@@ -0,0 +1,21 @@
+package utils;
+
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import play.libs.F;
+import play.mvc.Action;
+import play.mvc.Http;
+import play.mvc.Result;
+
+public class Headers extends Action.Simple {
+
+    private static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'").withZoneUTC();
+
+    @Override
+    public F.Promise<Result> call(Http.Context context) throws Throwable {
+        context.response().setHeader("Server", "play2-java-jpa");
+        context.response().setHeader("Date", RFC_1123_DATE_TIME.print(new DateTime()));
+        return delegate.call(context);
+    }
+}

+ 8 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Predicate.java

@@ -0,0 +1,8 @@
+package utils;
+
+/**
+ * Predicates for PredicatedActions.
+ */
+public interface Predicate {
+    boolean condition();
+}

+ 26 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/Predicated.java

@@ -0,0 +1,26 @@
+package utils;
+
+import play.mvc.With;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Declares a composing action that will check for a condition before deciding on whether to proceed with the request.
+ */
+@With(PredicatedAction.class)
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Predicated {
+    /**
+     * The condition.
+     */
+    Class<? extends Predicate> predicate();
+
+    /**
+     * The http status code to return if the condition fails.
+     */
+    int failed();
+}

+ 23 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/utils/PredicatedAction.java

@@ -0,0 +1,23 @@
+package utils;
+
+/**
+ * A predicated action is one where a condition must be satisfied in order to proceed with the request. If the
+ * condition is not satisfied then a supplied status result is yielded.
+ */
+
+import play.libs.F;
+import play.mvc.Action;
+import play.mvc.Http;
+import play.mvc.Result;
+
+public class PredicatedAction extends Action<Predicated> {
+    @Override
+    public F.Promise<Result> call(final Http.Context ctx) throws Throwable {
+        final Predicate p = configuration.predicate().newInstance();
+        if (p.condition()) {
+            return delegate.call(ctx);
+        } else {
+            return F.Promise.<Result>pure(status(configuration.failed()));
+        }
+    }
+}

+ 16 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/views/fortunes.scala.html

@@ -0,0 +1,16 @@
+@(fortunes: List[Fortune])
+
+@main() {
+    <table>
+        <tr>
+            <th>id</th>
+            <th>message</th>
+        </tr>
+        @for(fortune <- fortunes) {
+        <tr>
+            <td>@fortune.id</td>
+            <td>@fortune.message</td>
+        </tr>
+        }
+    </table>
+}

+ 12 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/views/main.scala.html

@@ -0,0 +1,12 @@
+@()(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+    @content
+    </body>
+</html>

+ 17 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/build.sbt

@@ -0,0 +1,17 @@
+name := """play2-java-jpa-hikaricp"""
+
+version := "1.0-SNAPSHOT"
+
+lazy val root = (project in file(".")).enablePlugins(PlayJava)
+
+scalaVersion := "2.11.2"
+
+libraryDependencies ++= Seq(
+  javaJdbc,
+  javaJpa,
+  "mysql" % "mysql-connector-java" % "5.1.33",
+  "org.hibernate" % "hibernate-entitymanager" % "4.3.6.Final",
+  "com.edulify" %% "play-hikaricp" % "1.5.0"
+)
+
+resolvers += Resolver.url("Edulify Repository", url("http://edulify.github.io/modules/releases/"))(Resolver.ivyStylePatterns)

+ 14 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/META-INF/persistence.xml

@@ -0,0 +1,14 @@
+<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">
+             
+    <persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
+        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
+        <non-jta-data-source>DefaultDS</non-jta-data-source>
+        <properties>
+            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+        </properties>
+    </persistence-unit>
+    
+</persistence>

+ 97 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf

@@ -0,0 +1,97 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="`o0VB@vXStsF:ffwM5ZZ_r:GYkm96QM[nRUJLpEbI8hwLUdV;N<:UyUWI;lf/XP`"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `conf/my.application.Router`,
+# you may need to define a router file `my.application.routes`.
+# Default to Routes in the root package (and `conf/routes`)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+#
+# You can expose this datasource via JNDI if needed (Useful for JPA)
+# db.default.jndiName=DefaultDS
+
+db.default.driver= com.mysql.jdbc.Driver
+db.default.url="jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+db.default.user=benchmarkdbuser
+db.default.password=benchmarkdbpass
+db.default.jndiName=DefaultDS
+jpa.default=defaultPersistenceUnit
+
+db.default.partitionCount=4
+
+# The number of connections to create per partition. Setting this to
+# 5 with 3 partitions means you will have 15 unique connections to the
+# database. Note that BoneCP will not create all these connections in
+# one go but rather start off with minConnectionsPerPartition and
+# gradually increase connections as required.
+#
+# This value maps to the maximumPoolSize for HickariCP (db.default.partitionCount * db.default.maxConnectionsPerPartition)
+db.default.maxConnectionsPerPartition=64
+
+# The number of initial connections, per partition.
+#
+# This maps to the minimumIdle connections for HikariCP (db.default.partitionCount * db.default.minConnectionsPerPartition)
+db.default.minConnectionsPerPartition=64
+
+dbplugin=disabled
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+evolutionplugin=disabled
+
+# Ebean configuration
+# ~~~~~
+# You can declare as many Ebean servers as you want.
+# By convention, the default server is named `default`
+#
+# ebean.default="models.*"
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+

+ 1 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/play.plugins

@@ -0,0 +1 @@
+200:com.edulify.play.hikaricp.HikariCPPlugin

+ 13 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/routes

@@ -0,0 +1,13 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+GET        /json                controllers.Application.json
+GET        /db                  controllers.Application.db()
+GET        /queries             controllers.Application.queries(queries ?= "1")
+GET        /fortunes            controllers.Application.fortunes
+GET        /update              controllers.Application.update(queries ?= "1")
+GET        /plaintext           controllers.Application.plainText
+
+# Map static resources from the /public folder to the /assets URL path
+GET        /assets/*file        controllers.Assets.at(path="/public", file)

+ 1 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/build.properties

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

+ 4 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt

@@ -0,0 +1,4 @@
+resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
+
+// The Play plugin
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.6")

+ 11 - 0
frameworks/Java/play2-java/play2-java-jpa-hikaricp/source_code

@@ -0,0 +1,11 @@
+./play-java-jpa/app/
+./play-java-jpa/app/controllers
+./play-java-jpa/app/controllers/Application.java
+./play-java-jpa/app/utils
+./play-java-jpa/app/utils/Headers.java
+./play-java-jpa/app/utils/Predicate.java
+./play-java-jpa/app/utils/PredicatedAction.java
+./play-java-jpa/app/utils/Predicated.java
+./play-java-jpa/app/models
+./play-java-jpa/app/models/World.java
+./play-java-jpa/app/models/Fortune.java

+ 18 - 6
frameworks/Java/play2-java/play2-java-jpa/README.md

@@ -4,25 +4,37 @@ This is the Play portion of a [benchmarking test suite](../) comparing a variety
 
 ### JSON Encoding Test
 
-* [JSON test source](app/controllers/Application.java)
+* [JSON test controller](app/controllers/Application.java)
 
 ### Data-Store/Database Mapping Test
 
 * [Database test controller](app/controllers/Application.java)
-* [Database test model](app/models/World.java)
+* [Database World test model](app/models/World.java)
+* [Database Fortune test model](app/models/Fortune.java)
+
+### Plain Text Test
+
+* [Plain text test controller](app/controllers/Application.java)
 
 ## Infrastructure Software Versions
 The tests were run with:
 
 * [Java OpenJDK 1.7](http://openjdk.java.net/)
-* [Play 2.3.3](http://http://www.playframework.com/)
+* [Play 2.3.6](http://http://www.playframework.com/)
 
 ## Test URLs
 ### JSON Encoding Test
 
-http://localhost/json
+* http://localhost/json
 
 ### Data-Store/Database Mapping Test
 
-http://localhost/db
-http://localhost/queries?queries=10
+* http://localhost/db
+* http://localhost/queries?queries=10
+* http://localhost/fortunes
+* http://localhost/update?queries=10
+
+### Plain Text Test
+
+* http://localhost/plaintext
+

+ 51 - 10
frameworks/Java/play2-java/play2-java-jpa/app/controllers/Application.java

@@ -3,6 +3,7 @@ package controllers;
 import akka.dispatch.ExecutionContexts;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import models.Fortune;
 import models.World;
 import play.Play;
 import play.core.NamedThreadFactory;
@@ -14,9 +15,7 @@ import scala.concurrent.ExecutionContext;
 import utils.Predicate;
 import utils.Predicated;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -24,7 +23,6 @@ import java.util.concurrent.TimeUnit;
 
 public class Application extends Controller {
 
-    private static final int MAX_QUERIES_PER_REQUEST = 20;
     private static final int TEST_DATABASE_ROWS = 10000;
     private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
 
@@ -69,6 +67,54 @@ public class Application extends Controller {
 
     @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
     public static F.Promise<Result> queries(final String queryCountString) {
+        return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
+            @Override
+            public Result apply(List<World> worlds) {
+                return ok(Json.toJson(worlds));
+            }
+        });
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> fortunes() {
+        return F.Promise.promise(new F.Function0<Result>() {
+
+            @Override
+            public Result apply() throws Throwable {
+                List<Fortune> fortunes = Fortune.findAll();
+                fortunes.add(new Fortune("Additional fortune added at request time."));
+                Collections.sort(fortunes, new Comparator<Fortune>() {
+                    @Override
+                    public int compare(Fortune f1, Fortune f2) {
+                        return f1.message.compareTo(f2.message);
+                    }
+                });
+                return ok(views.html.fortunes.render(fortunes));
+            }
+        }, dbEc);
+    }
+
+    @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
+    public static F.Promise<Result> update(final String queryCountString) {
+        return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
+            @Override
+            public Result apply(List<World> worlds) throws Throwable {
+                Random random = ThreadLocalRandom.current();
+                for (World world : worlds) {
+                    world.randomNumber = (long) (random.nextInt(10000) + 1);
+                }
+
+                worlds = World.save(worlds);
+                return ok(Json.toJson(worlds));
+            }
+        });
+    }
+
+    public static Result plainText() {
+        return ok("Hello, World!");
+    }
+
+    private static int queryCount(String queryCountString) {
         int queryCount;
         try {
             queryCount = Integer.parseInt(queryCountString, 10);
@@ -81,12 +127,7 @@ public class Application extends Controller {
             queryCount = 500;
         }
 
-        return getRandomWorlds(queryCount).map(new F.Function<List<World>, Result>() {
-            @Override
-            public Result apply(List<World> worlds) {
-                return ok(Json.toJson(worlds));
-            }
-        });
+        return queryCount;
     }
 
     private static F.Promise<List<World>> getRandomWorlds(final int n) {

+ 34 - 0
frameworks/Java/play2-java/play2-java-jpa/app/models/Fortune.java

@@ -0,0 +1,34 @@
+package models;
+
+import play.db.jpa.JPA;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.criteria.CriteriaQuery;
+import java.util.List;
+
+@Entity
+public class Fortune {
+
+    @Id
+    public Long id = 0L;
+
+    public String message;
+
+    public Fortune() {
+    }
+
+    public Fortune(String message) {
+        this.message = message;
+    }
+
+    public static List<Fortune> findAll() throws Throwable {
+        return JPA.withTransaction("default", true, new play.libs.F.Function0<List<Fortune>>() {
+            public List<Fortune> apply() {
+                CriteriaQuery<Fortune> criteria = JPA.em().getCriteriaBuilder().createQuery(Fortune.class);
+                criteria.select(criteria.from(Fortune.class));
+                return JPA.em().createQuery(criteria).getResultList();
+            }
+        });
+    }
+}

+ 21 - 6
frameworks/Java/play2-java/play2-java-jpa/app/models/World.java

@@ -1,9 +1,12 @@
 package models;
 
-import javax.persistence.*;
-
 import play.db.jpa.JPA;
 
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.List;
+
 @Entity
 public class World {
 
@@ -14,10 +17,22 @@ public class World {
     public Long randomNumber;
 
     public static World findById(final Long id) throws Throwable {
-      return JPA.withTransaction("default", true, new play.libs.F.Function0<World>() {
-        public World apply() {
-            return JPA.em().find(World.class, id);
+        return JPA.withTransaction("default", true, new play.libs.F.Function0<World>() {
+            public World apply() {
+                return JPA.em().find(World.class, id);
+            }
+        });
+    }
+
+    public static List<World> save(final List<World> worlds) throws Throwable {
+        for (final World world : worlds) {
+            JPA.withTransaction("default", false, new play.libs.F.Function0<World>() {
+                public World apply() {
+                    return JPA.em().merge(world);
+                }
+            });
         }
-      });
+
+        return worlds;
     }
 }

+ 21 - 0
frameworks/Java/play2-java/play2-java-jpa/app/utils/Headers.java

@@ -0,0 +1,21 @@
+package utils;
+
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import play.libs.F;
+import play.mvc.Action;
+import play.mvc.Http;
+import play.mvc.Result;
+
+public class Headers extends Action.Simple {
+
+    private static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'").withZoneUTC();
+
+    @Override
+    public F.Promise<Result> call(Http.Context context) throws Throwable {
+        context.response().setHeader("Server", "play2-java-jpa");
+        context.response().setHeader("Date", RFC_1123_DATE_TIME.print(new DateTime()));
+        return delegate.call(context);
+    }
+}

+ 16 - 0
frameworks/Java/play2-java/play2-java-jpa/app/views/fortunes.scala.html

@@ -0,0 +1,16 @@
+@(fortunes: List[Fortune])
+
+@main() {
+    <table>
+        <tr>
+            <th>id</th>
+            <th>message</th>
+        </tr>
+        @for(fortune <- fortunes) {
+        <tr>
+            <td>@fortune.id</td>
+            <td>@fortune.message</td>
+        </tr>
+        }
+    </table>
+}

+ 12 - 0
frameworks/Java/play2-java/play2-java-jpa/app/views/main.scala.html

@@ -0,0 +1,12 @@
+@()(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+    @content
+    </body>
+</html>

+ 1 - 1
frameworks/Java/play2-java/play2-java-jpa/build.sbt

@@ -9,7 +9,7 @@ lazy val root = (project in file(".")).enablePlugins(PlayJava)
 libraryDependencies ++= Seq(
   javaJdbc,
   javaJpa,
-  "mysql" % "mysql-connector-java" % "5.1.32",
+  "mysql" % "mysql-connector-java" % "5.1.33",
   "org.hibernate" % "hibernate-entitymanager" % "4.3.6.Final"
   )
 

+ 3 - 1
frameworks/Java/play2-java/play2-java-jpa/conf/routes

@@ -2,10 +2,12 @@
 # This file defines all application routes (Higher priority routes first)
 # ~~~~
 
-# Home page
 GET        /json                controllers.Application.json
 GET        /db                  controllers.Application.db()
 GET        /queries             controllers.Application.queries(queries ?= "1")
+GET        /fortunes            controllers.Application.fortunes
+GET        /update              controllers.Application.update(queries ?= "1")
+GET        /plaintext           controllers.Application.plainText
 
 # Map static resources from the /public folder to the /assets URL path
 GET        /assets/*file        controllers.Assets.at(path="/public", file)

+ 1 - 1
frameworks/Java/play2-java/play2-java-jpa/project/plugins.sbt

@@ -5,4 +5,4 @@ logLevel := Level.Warn
 resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
 
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.4")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.6")

+ 2 - 0
frameworks/Java/play2-java/play2-java-jpa/source_code

@@ -2,8 +2,10 @@
 ./play-java-jpa/app/controllers
 ./play-java-jpa/app/controllers/Application.java
 ./play-java-jpa/app/utils
+./play-java-jpa/app/utils/Headers.java
 ./play-java-jpa/app/utils/Predicate.java
 ./play-java-jpa/app/utils/PredicatedAction.java
 ./play-java-jpa/app/utils/Predicated.java
 ./play-java-jpa/app/models
 ./play-java-jpa/app/models/World.java
+./play-java-jpa/app/models/Fortune.java

+ 6 - 0
frameworks/Java/play2-java/setup_java_jpa_hikaricp.py

@@ -0,0 +1,6 @@
+
+# This file was generated by frameworks/Java/play2-java/generate_config.py.
+# Do not edit this file directly, use the script to regenerate.
+from .setup_common import make_setup_for_dir
+
+make_setup_for_dir(globals(), 'play2-java-jpa-hikaricp')