Browse Source

Merge branch 'jersey-mustache' of https://github.com/trautonen/FrameworkBenchmarks into trautonen-jersey-mustache

Patrick Falls 12 years ago
parent
commit
71a67e05c2

+ 24 - 4
grizzly-jersey/README.md

@@ -2,17 +2,37 @@
 
 This is the Grizzly+Jersey portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
-### JSON Encoding Test
-* [JSON test source](src/main/java/hello/HelloResource.java)
+### JSON serialization test
+* [JSON test resource](src/main/java/hello/JsonResource.java)
+
+### Database tests
+* [Database tests resource](src/main/java/hello/DbResource.java)
+
+### Fortunes test
+* [Fortunes test resource](src/main/java/hello/FortunesResource.java)
 
 ## Versions
 
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
 * [Jersey 1.17.1](http://jersey.java.net/)
-* [Grizzly 2.2.16](http://grizzly.java.net/)
+* [Grizzly 2.3.2](http://grizzly.java.net/)
+* [Jackson 2.2.1](http://wiki.fasterxml.com/JacksonHome)
+* [Mustache.java 0.8.12](https://github.com/spullara/mustache.java)
+* [Jersey Mustache 1.0.0](https://github.com/trautonen/jersey-mustache)
+* [Hibernate 4.2.1](http://www.hibernate.org/)
 
 ## Test URLs
 
-### JSON Encoding Test
+### JSON serialization test
 
     http://localhost:8080/json
+
+### Database tests
+
+    http://localhost:8080/db
+
+    http://localhost:8080/db?queries=10
+
+### Fortunes test
+
+    http://localhost:8080/fortunes

+ 3 - 0
grizzly-jersey/benchmark_config

@@ -4,6 +4,9 @@
     "default": {
       "setup_file": "setup",
       "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
       "port": 8080,
       "sort": 38
     }

+ 76 - 8
grizzly-jersey/pom.xml

@@ -9,34 +9,102 @@
 
   <packaging>jar</packaging>
 
+  <prerequisites>
+    <maven>3.0</maven>
+  </prerequisites>
+
+  <properties>
+    <grizzly.version>2.3.2</grizzly.version>
+    <jersey.version>1.17.1</jersey.version>
+    <jersey-mustache.version>1.0.0</jersey-mustache.version>
+    <jackson.version>2.2.1</jackson.version>
+    <mustache.version>0.8.12</mustache.version>
+    <hibernate.version>4.2.1.Final</hibernate.version>
+    <mysql-connector.version>5.1.25</mysql-connector.version>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>com.sun.jersey</groupId>
       <artifactId>jersey-server</artifactId>
-      <version>1.17.1</version>
     </dependency>
     <dependency>
       <groupId>com.sun.jersey</groupId>
       <artifactId>jersey-grizzly2</artifactId>
-      <version>1.17.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eluder.jersey</groupId>
+      <artifactId>jersey-mustache</artifactId>
+      <version>${jersey-mustache.version}</version>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
-      <version>2.1.4</version>
+      <version>${jackson.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-core</artifactId>
+      <version>${hibernate.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-c3p0</artifactId>
+      <version>${hibernate.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+      <version>${mysql-connector.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>
+      <version>1.2</version>
     </dependency>
   </dependencies>
+  
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>com.sun.jersey</groupId>
+        <artifactId>jersey-server</artifactId>
+        <version>${jersey.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.sun.jersey</groupId>
+        <artifactId>jersey-grizzly2</artifactId>
+        <version>${jersey.version}</version>
+      </dependency>
+      <dependency>
+      	<groupId>org.glassfish.grizzly</groupId>
+      	<artifactId>grizzly-http</artifactId>
+      	<version>${grizzly.version}</version>
+      </dependency>
+      <dependency>
+      	<groupId>org.glassfish.grizzly</groupId>
+      	<artifactId>grizzly-http-server</artifactId>
+      	<version>${grizzly.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.github.spullara.mustache.java</groupId>
+        <artifactId>compiler</artifactId>
+        <version>${mustache.version}</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
 
   <build>
+    <finalName>${project.artifactId}</finalName>
     <plugins>
       <plugin>
         <inherited>true</inherited>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>2.3.2</version>
+        <version>3.1</version>
         <configuration>
-          <source>1.6</source>
-          <target>1.6</target>
+          <source>1.7</source>
+          <target>1.7</target>
           <optimize>true</optimize>
           <debug>false</debug>
         </configuration>
@@ -44,7 +112,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-shade-plugin</artifactId>
-        <version>1.5</version>
+        <version>2.0</version>
         <executions>
           <execution>
             <phase>package</phase>
@@ -55,7 +123,7 @@
               <transformers>
                 <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                  <mainClass>hello.HelloWebServer</mainClass>
+                  <mainClass>hello.JerseyWebServer</mainClass>
                 </transformer>
               </transformers>
             </configuration>

+ 1 - 1
grizzly-jersey/setup.py

@@ -6,7 +6,7 @@ import os
 def start(args):
   try:
     subprocess.check_call("mvn clean package", shell=True, cwd="grizzly-jersey")
-    subprocess.Popen("java -jar target/grizzly-jersey-example-0.1.jar".rsplit(" "), cwd="grizzly-jersey")
+    subprocess.Popen(("java -jar target/grizzly-jersey-example.jar -dbhost " + args.database_host).rsplit(" "), cwd="grizzly-jersey")
     return 0
   except subprocess.CalledProcessError:
     return 1

+ 45 - 0
grizzly-jersey/src/main/java/hello/DbResource.java

@@ -0,0 +1,45 @@
+package hello;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import hello.domain.World;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import com.sun.jersey.spi.resource.Singleton;
+
+@Singleton
+@Path("/db")
+public class DbResource {
+
+  private static final int DB_ROWS = 10000;
+  
+  @Context
+  private SessionFactory sessionFactory;
+  
+  @GET
+  @Produces(APPLICATION_JSON + "; charset=utf-8")
+  public Object db(@QueryParam("queries") @DefaultValue("1") final int queries) {
+    final World[] worlds = new World[queries];
+    final Random random = ThreadLocalRandom.current();
+    final Session session = sessionFactory.openSession();
+    
+    for (int i = 0; i < queries; i++) {
+        worlds[i] = (World) session.byId(World.class).load(random.nextInt(DB_ROWS) + 1);
+    }
+    
+    session.close();
+    return worlds;
+  }
+  
+}

+ 47 - 0
grizzly-jersey/src/main/java/hello/FortunesResource.java

@@ -0,0 +1,47 @@
+package hello;
+
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import hello.domain.Fortune;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.spi.resource.Singleton;
+
+@Singleton
+@Path("/fortunes")
+public class FortunesResource {
+
+  @Context
+  private SessionFactory sessionFactory;
+  
+  @GET
+  @Produces(TEXT_HTML + "; charset=utf-8")
+  public Viewable fortunes() {
+    final Session session = sessionFactory.openSession();
+    final List fortunes = new ArrayList(session.createCriteria(Fortune.class).list());
+    fortunes.add(new Fortune(0, "Additional fortune added at request time."));
+    Collections.sort(fortunes);
+    
+    session.close();
+    return new Viewable("/fortunes.mustache", new Scope(fortunes));
+  }
+  
+  public static class Scope {
+    public List fortunes;
+    
+    public Scope(final List fortunes) {
+      this.fortunes = fortunes;
+    }
+  }
+}

+ 0 - 41
grizzly-jersey/src/main/java/hello/HelloWebServer.java

@@ -1,41 +0,0 @@
-package hello;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-
-import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory;
-import com.sun.jersey.api.core.PackagesResourceConfig;
-import com.sun.jersey.api.core.ResourceConfig;
-
-public class HelloWebServer {
-
-  private final int port;
-
-  public HelloWebServer(int port) {
-    this.port = port;
-  }
-
-  public void run() throws Exception {
-    URI baseUri = getBaseUrl(port);
-    ResourceConfig rc = new PackagesResourceConfig("hello");
-    GrizzlyServerFactory.createHttpServer(baseUri, rc);
-    
-    System.err.print("Server started. Press ENTER to stop.");
-    System.in.read();
-  }
-
-  private static URI getBaseUrl(int port) {
-    return UriBuilder.fromUri("http://0.0.0.0/").port(port).build();
-  }
-
-  public static void main(String[] args) throws Exception {
-    int port;
-    if (args.length > 0) {
-      port = Integer.parseInt(args[0]);
-    } else {
-      port = 8080;
-    }
-    new HelloWebServer(port).run();
-  }
-}

+ 72 - 0
grizzly-jersey/src/main/java/hello/JerseyWebServer.java

@@ -0,0 +1,72 @@
+package hello;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.Options;
+import org.glassfish.grizzly.http.server.HttpServer;
+
+import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory;
+import com.sun.jersey.api.core.PackagesResourceConfig;
+import com.sun.jersey.api.core.ResourceConfig;
+
+public class JerseyWebServer {
+
+  private final int port;
+  private final String dbHost;
+  private final int dbPort;
+
+  public JerseyWebServer(final int port, final String dbHost, final int dbPort) {
+    this.port = port;
+    this.dbHost = dbHost;
+    this.dbPort = dbPort;
+  }
+
+  public void run() throws Exception {
+    URI baseUri = getBaseUrl(port);
+    ResourceConfig rc = new PackagesResourceConfig("hello", "org.eluder.jersey.mustache");
+    rc.setPropertiesAndFeatures(properties());
+    rc.getContainerResponseFilters().add(new ServerResponseFilter());
+    HttpServer server = GrizzlyServerFactory.createHttpServer(baseUri, rc);
+    
+    System.err.print("Server started. Press ENTER to stop.");
+    System.in.read();
+    server.stop();
+  }
+
+  private Map<String, Object> properties() {
+    Map<String, Object> properties = new HashMap<String, Object>();
+    properties.put("dbhost", dbHost);
+    properties.put("dbport", dbPort);
+    return properties;
+  }
+  
+  private static URI getBaseUrl(final int port) {
+    return UriBuilder.fromUri("http://0.0.0.0/").port(port).build();
+  }
+
+  public static void main(final String[] args) throws Exception {
+    CommandLineParser parser = new BasicParser();
+    CommandLine cmd = parser.parse(options(), args);
+    
+    int port = Integer.parseInt(cmd.getOptionValue("port", "8080"));
+    String dbHost = cmd.getOptionValue("dbhost", "localhost");
+    int dbPort = Integer.parseInt(cmd.getOptionValue("dbport", "3306"));
+    
+    new JerseyWebServer(port,dbHost, dbPort).run();
+  }
+  
+  private static Options options() {
+    Options options = new Options();
+    options.addOption("port", true, "server port");
+    options.addOption("dbhost", true, "database host");
+    options.addOption("dbport", true, "database port");
+    return options;
+  }
+}

+ 22 - 19
grizzly-jersey/src/main/java/hello/JsonMessageBodyWriter.java

@@ -1,6 +1,6 @@
 package hello;
 
-import static javax.ws.rs.core.MediaType.*;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -15,40 +15,43 @@ import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.sun.jersey.spi.resource.Singleton;
 
 @Provider
+@Singleton
 @Produces(APPLICATION_JSON)
 public class JsonMessageBodyWriter implements MessageBodyWriter<Object> {
-  private static final ObjectMapper mapper = new ObjectMapper();
+  
+  private final ObjectMapper mapper = new ObjectMapper();
 
   @Override
   public boolean isWriteable(
-      Class<?> type,
-      Type genericType,
-      Annotation[] annotations,
-      MediaType mediaType) {
-    return APPLICATION_JSON_TYPE.equals(mediaType);
+      final Class<?> type,
+      final Type genericType,
+      final Annotation[] annotations,
+      final MediaType mediaType) {
+    return "json".equals(mediaType.getSubtype());
   }
 
   @Override
   public long getSize(
-      Object t,
-      Class<?> type,
-      Type genericType,
-      Annotation[] annotations,
-      MediaType mediaType) {
+      final Object t,
+      final Class<?> type,
+      final Type genericType,
+      final Annotation[] annotations,
+      final MediaType mediaType) {
     return -1; // We can't predict the output size at this point
   }
 
   @Override
   public void writeTo(
-      Object t,
-      Class<?> type,
-      Type genericType,
-      Annotation[] annotations,
-      MediaType mediaType,
-      MultivaluedMap<String, Object> httpHeaders,
-      OutputStream entityStream)
+      final Object t,
+      final Class<?> type,
+      final Type genericType,
+      final Annotation[] annotations,
+      final MediaType mediaType,
+      final MultivaluedMap<String, Object> httpHeaders,
+      final OutputStream entityStream)
       throws IOException, WebApplicationException {
     mapper.writeValue(entityStream, t);
   }

+ 5 - 4
grizzly-jersey/src/main/java/hello/HelloResource.java → grizzly-jersey/src/main/java/hello/JsonResource.java

@@ -13,11 +13,12 @@ import com.sun.jersey.spi.resource.Singleton;
 
 @Singleton
 @Path("/json")
-public class HelloResource {
+public class JsonResource {
+  
   @GET
-  @Produces(APPLICATION_JSON)
-  public Object hello() {
-    Map<String, String> data = new HashMap<String, String>();
+  @Produces(APPLICATION_JSON + "; charset=utf-8")
+  public Object json() {
+    Map<String, String> data = new HashMap<String, String>(1);
     data.put("message", "Hello, World!");
     return data;
   }

+ 18 - 0
grizzly-jersey/src/main/java/hello/ServerResponseFilter.java

@@ -0,0 +1,18 @@
+package hello;
+
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerResponse;
+import com.sun.jersey.spi.container.ContainerResponseFilter;
+
+public class ServerResponseFilter implements ContainerResponseFilter {
+  
+  private static final String SERVER_HEADER = "Server";
+  private static final String SERVER_VALUE  = "Grizzly";
+  
+  @Override
+  public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response) {
+    response.getHttpHeaders().add(SERVER_HEADER, SERVER_VALUE);
+    return response;
+  }
+
+}

+ 35 - 0
grizzly-jersey/src/main/java/hello/SessionFactoryProvider.java

@@ -0,0 +1,35 @@
+package hello;
+
+import hello.domain.Fortune;
+import hello.domain.World;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.Provider;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.service.ServiceRegistryBuilder;
+
+import com.sun.jersey.api.core.ResourceConfig;
+import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider;
+import com.sun.jersey.spi.resource.Singleton;
+
+@Provider
+@Singleton
+public class SessionFactoryProvider extends SingletonTypeInjectableProvider<Context, SessionFactory> {
+
+  public SessionFactoryProvider(@Context final ResourceConfig rc) {
+    super(SessionFactory.class, createSessionFactory(rc));
+  }
+  
+  private static SessionFactory createSessionFactory(final ResourceConfig rc) {
+    Configuration configuration = new Configuration().configure();
+    String url = configuration.getProperty("hibernate.connection.url");
+    url = url.replace("//localhost:3306/", "//" + rc.getProperty("dbhost") + ":" + rc.getProperty("dbport") + "/");
+    configuration.setProperty("hibernate.connection.url", url);
+    configuration.addAnnotatedClass(World.class);
+    configuration.addAnnotatedClass(Fortune.class);
+    ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder().applySettings(configuration.getProperties());
+    return configuration.buildSessionFactory(serviceRegistryBuilder.buildServiceRegistry());
+  }
+}

+ 28 - 0
grizzly-jersey/src/main/java/hello/domain/Fortune.java

@@ -0,0 +1,28 @@
+package hello.domain;
+
+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(final int id, final String message) {
+    this.id = id;
+    this.message = message;
+  }
+  
+  @Override
+  public int compareTo(final Fortune other)
+  {
+    return message.compareTo(other.message);
+  }
+}

+ 16 - 0
grizzly-jersey/src/main/java/hello/domain/World.java

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

+ 20 - 0
grizzly-jersey/src/main/resources/fortunes.mustache

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

+ 16 - 0
grizzly-jersey/src/main/resources/hibernate.cfg.xml

@@ -0,0 +1,16 @@
+<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
+<hibernate-configuration>
+  <session-factory>
+    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
+    <property name="hibernate.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</property>
+    <property name="hibernate.connection.username">benchmarkdbuser</property>
+    <property name="hibernate.connection.password">benchmarkdbpass</property>
+    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
+    <property name="hibernate.cache.use_query_cache">false</property>
+    <property name="hibernate.show_sql">false</property>
+    <property name="hibernate.c3p0.min_size">5</property>
+    <property name="hibernate.c3p0.max_size">40</property>
+    <property name="hibernate.c3p0.timeout">1800</property>
+    <property name="hibernate.c3p0.max_statements">50</property>
+  </session-factory>
+</hibernate-configuration>