Browse Source

Test for Spark framework.

trautonen 12 years ago
parent
commit
2d0e89e53b

+ 52 - 0
spark/README.md

@@ -0,0 +1,52 @@
+# Spark Benchmarking Test
+
+This is the Spark portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+The test utilizes Spark routes, Gson for JSON serialization, Hibernate for ORM and a custom OSIV pattern created
+with Spark filters.
+
+
+## Tests
+
+* [Spark application](/src/main/java/hello/web/SparkApplication.java)
+* [Hibernate](http://www.hibernate.org/) configuration for local datasource and container managed JNDI
+** [JNDI configuration](/world/src/main/resources/hibernate-jndi.cfg.xml)
+** [Local datasource configuration](/world/src/main/resources/hibernate-local.cfg.xml)
+** [Hibernate utilities](/src/main/java/hello/web/HibernateUtil.java)
+** [Database entity](/src/main/java/hello/domain/World.java)
+
+
+## Infrastructure Software Versions
+
+* [Spark 0.9.9.7-SNAPSHOT](http://www.sparkjava.com/)
+* [Hibernate 4.2.0.Final](http://www.hibernate.org/)
+* [Gson 2.2.2](https://code.google.com/p/google-gson/)
+
+
+## Different test setups
+
+* Local environment with Spark's built in embedded jetty (port=4567, context=/)
+** Start application from [SparkApplication](/world/src/main/java/hello/web/SparkApplication.java)'s main method
+** 'standalone' maven profile must be enabled from [pom.xml](/pom.xml)
+* Local environment with Tomcat maven plugin (port=8080, context=/spark)
+** Start application with maven command 'mvn clean tomcat7:run'
+** No maven profiles must be enabled
+* Any servlet container with built WAR (port=any, context=/spark)
+** Create war with maven command 'mvn clean package'
+** No maven profiles must be enabled
+** Built war can be copied from /target/spark.war
+
+* Local datasource or JNDI datasource can be configured with system property 'jndi'
+** -Djndi=true or no property for JNDI datasource
+** -Djndi=false for local datasource
+
+## Test URLs
+
+### JSON Encoding Test
+
+http://localhost:4567/json
+http://localhost:8080/spark/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost:4567/db?queries=5
+http://localhost:8080/spring/db?queries=5

+ 0 - 0
spark/__init__.py


+ 13 - 0
spark/benchmark_config

@@ -0,0 +1,13 @@
+{
+  "framework": "spark",
+  "tests": [{
+    "default": {
+      "setup_file": "setup.py",
+      "json_url": "/spark/json",
+      "db_url": "/spark/db",
+      "query_url": "/spark/db?queries=",
+      "port": 8080,
+      "sort": 49
+    }
+  }]
+}

+ 132 - 0
spark/pom.xml

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>hello.world</groupId>
+    <artifactId>hello-spark</artifactId>
+    <name>Spark Test project</name>
+    <packaging>war</packaging>
+    <version>1.0.0-BUILD-SNAPSHOT</version>
+
+    <properties>
+        <java-version>1.7</java-version>
+        <spark-version>0.9.9.7-SNAPSHOT</spark-version>
+        <hibernate-version>4.2.0.Final</hibernate-version>
+        <gson-version>2.2.2</gson-version>
+        <mysql-connector-version>5.1.24</mysql-connector-version>
+        <slf4j-version>1.7.5</slf4j-version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.sparkjava</groupId>
+            <artifactId>spark-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>${gson-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>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+        </dependency>
+    </dependencies>
+    
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.sparkjava</groupId>
+                <artifactId>spark-core</artifactId>
+                <version>${spark-version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.eclipse.jetty</groupId>
+                        <artifactId>jetty-server</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.eclipse.jetty</groupId>
+                        <artifactId>jetty-webapp</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>${slf4j-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-log4j12</artifactId>
+                <version>${slf4j-version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    
+    <profiles>
+        <profile>
+            <id>standalone</id>
+            <dependencyManagement>
+                <dependencies>
+                    <dependency>
+                        <groupId>com.sparkjava</groupId>
+                        <artifactId>spark-core</artifactId>
+                        <version>${spark-version}</version>
+                    </dependency>
+                </dependencies>
+            </dependencyManagement>
+        </profile>
+    </profiles>
+    
+    <repositories>
+        <repository>
+            <id>Spark repository</id>
+            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+        </repository>
+    </repositories>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java-version}</source>
+                    <target>${java-version}</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <warName>spark</warName>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.tomcat.maven</groupId>
+                <artifactId>tomcat7-maven-plugin</artifactId>
+                <version>2.1</version>
+                    <configuration>
+                        <systemProperties>
+                            <jndi>false</jndi>
+                        </systemProperties>
+                    </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 22 - 0
spark/setup.py

@@ -0,0 +1,22 @@
+
+import subprocess
+import sys
+import setup_util
+
+def start(args):
+  setup_util.replace_text("spark/src/main/webapp/WEB-INF/resin-web.xml", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
+  
+  try:
+    subprocess.check_call("mvn clean package", shell=True, cwd="spark")
+    subprocess.check_call("rm -rf $RESIN_HOME/webapps/*", shell=True)
+    subprocess.check_call("cp spark/target/spark.war $RESIN_HOME/webapps/spark.war", shell=True)
+    subprocess.check_call("$RESIN_HOME/bin/resinctl start", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.check_call("$RESIN_HOME/bin/resinctl shutdown", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 7 - 0
spark/src/main/java/hello/domain/Message.java

@@ -0,0 +1,7 @@
+package hello.domain;
+
+public class Message {
+
+    public String message = "Hello world";
+
+}

+ 16 - 0
spark/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;
+    
+}

+ 54 - 0
spark/src/main/java/hello/web/HibernateUtil.java

@@ -0,0 +1,54 @@
+package hello.web;
+
+import hello.domain.World;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.service.ServiceRegistryBuilder;
+
+public class HibernateUtil {
+
+    private static final SessionFactory SESSION_FACTORY = createSessionFactory();
+    private static final ThreadLocal<Session> SESSIONS = new ThreadLocal<>();
+    
+    public static Session getSession() {
+        Session session = SESSIONS.get();
+        if (session == null) {
+            session = SESSION_FACTORY.openSession();
+            SESSIONS.set(session);
+        }
+        return session;
+    }
+    
+    public static void closeSession() {
+        Session session = SESSIONS.get();
+        if (session != null) {
+            session.close();
+            SESSIONS.remove();
+        }
+    }
+    
+    private static SessionFactory createSessionFactory() {
+        Configuration configuration = configuration();
+        configuration.setProperty("hibernate.dialect ", MySQLDialect.class.getName());
+        configuration.setProperty("hibernate.cache.use_query_cache", "false");
+        configuration.setProperty("show_sql", "false");
+        configuration.addAnnotatedClass(World.class);
+        ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder().applySettings(configuration.getProperties());
+        return configuration.buildSessionFactory(serviceRegistryBuilder.buildServiceRegistry());
+    }
+    
+    private static Configuration configuration() {
+        boolean jndi = Boolean.parseBoolean(System.getProperty("jndi", "true"));
+        Configuration configuration = new Configuration();
+        if (jndi) {
+            configuration.configure("/hibernate-jndi.cfg.xml");
+        } else {
+            configuration.configure("/hibernate-local.cfg.xml");
+        }
+        return configuration;
+    }
+    
+}

+ 69 - 0
spark/src/main/java/hello/web/SparkApplication.java

@@ -0,0 +1,69 @@
+package hello.web;
+
+import static spark.Spark.after;
+import static spark.Spark.get;
+import hello.domain.Message;
+import hello.domain.World;
+
+import java.util.Random;
+
+import org.hibernate.Session;
+
+import spark.Filter;
+import spark.Request;
+import spark.Response;
+import spark.Route;
+
+import com.google.gson.Gson;
+
+public class SparkApplication implements spark.servlet.SparkApplication {
+
+    private static final Gson   GSON                 = new Gson();
+    private static final Random RANDOM               = new Random();
+    private static final int    DB_ROWS              = 10000;
+    private static final String CONTENT_TYPE_JSON    = "application/json";
+    
+    @Override
+    public void init() {
+        get(new Route("/json") {
+            @Override
+            public Object handle(final Request request, final Response response) {
+                response.type(CONTENT_TYPE_JSON);
+                return GSON.toJson(new Message());
+            }
+        });
+        get(new Route("/db") {
+            @Override
+            public Object handle(final Request request, final Response response) {
+                response.type(CONTENT_TYPE_JSON);
+                int queries = getQueries(request);
+                
+                World[] worlds = new World[queries];
+                Session session = HibernateUtil.getSession();
+                
+                for (int i = 0; i < queries; i++) {
+                    worlds[i] = (World) session.byId(World.class).load(RANDOM.nextInt(DB_ROWS) + 1);
+                }
+
+                return GSON.toJson(worlds);
+            }
+            
+            private int getQueries(final Request request) {
+                String param = request.queryParams("queries");
+                return (param == null ? 1 : Integer.parseInt(param));
+            }
+        });
+        after(new Filter("/db") {
+            @Override
+            public void handle(final Request request, final Response response) {
+                HibernateUtil.closeSession();
+            }
+        });
+    }
+    
+    public static void main(final String[] args) {
+        System.setProperty("jndi", "false");
+        new SparkApplication().init();
+    }
+
+}

+ 8 - 0
spark/src/main/resources/hibernate-jndi.cfg.xml

@@ -0,0 +1,8 @@
+<!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.datasource">java:comp/env/jdbc/hello_world</property>
+    </session-factory>
+</hibernate-configuration>

+ 15 - 0
spark/src/main/resources/hibernate-local.cfg.xml

@@ -0,0 +1,15 @@
+<!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.c3p0.min_size">5</property>
+        <property name="hibernate.c3p0.max_size">20</property>
+        <property name="hibernate.c3p0.timeout">1800</property>
+        <property name="hibernate.c3p0.max_statements">50</property>
+    </session-factory>
+</hibernate-configuration>

+ 7 - 0
spark/src/main/resources/log4j.properties

@@ -0,0 +1,7 @@
+log4j.rootLogger=WARN, console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d %-5p %c %x - %m%n
+
+log4j.logger.hello=DEBUG

+ 13 - 0
spark/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>

+ 20 - 0
spark/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+ 
+    <filter>
+        <filter-name>SparkFilter</filter-name>
+        <filter-class>spark.servlet.SparkFilter</filter-class>
+        <init-param>
+            <param-name>applicationClass</param-name>
+            <param-value>hello.web.SparkApplication</param-value>
+        </init-param>
+    </filter>
+   
+    <filter-mapping>
+      <filter-name>SparkFilter</filter-name>
+      <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+</web-app>