Browse Source

Update Wicket to 7.5.0

* Use Jackson Afterburner
* Serialize to byte[] instead of String
* Reduce the number of response headers by disabling Wicket handling for caching headers
* Use custom IRequestMapper that directly matches on the request url instead of using Wicket's logic to calculate the best
Martin Tzvetanov Grigorov 8 years ago
parent
commit
54152ceb73

+ 7 - 12
frameworks/Java/wicket/README.md

@@ -3,31 +3,26 @@
 This is the wicket portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
 ### JSON Encoding Test
-* [JSON test source](src/main/java/hellowicket/HelloJsonResponse.java)
+* [JSON test source](src/main/java/hellowicket/HelloJsonResponse.java) - uses Jackson + Afterburner module
 
 ### Data-Store/Database Mapping Test
-Use [Hibernate](http://www.hibernate.org/) for interaction with MySQL database.
+Use JDBC for interaction with MySQL database.
 
 * [Database test source](src/main/java/hellowicket/HelloDbResponse.java)
 * [Database Entity](src/main/java/hellowicket/World.java)
-* [Hibernate Configuration](src/main/resources/hibernate.cfg.xml)
 
 ## Versions
 
-* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Wicket 6.12.0](http://wicket.apache.org/)
-* [Hibernate 4.1.1](http://www.hibernate.org/)
-* [MySQL 5.5.29](http://dev.mysql.com/)
-* [Maven 2.2.1](https://maven.apache.org/)
-* [Resin 4.0.34](http://www.caucho.com/)
-* [Jackson 2.3.0](http://wiki.fasterxml.com/JacksonHome)
+* [Wicket 7.5.0](http://wicket.apache.org/)
+* [MySQL 5.5.+](http://dev.mysql.com/)
+* [Jackson 2.8.5](http://wiki.fasterxml.com/JacksonHome)
 
 ## Test URLs
 
 ### JSON Encoding Test
 
-    http://localhost:8080/wicket/hello_json
+    http://localhost:8080/wicket/json
 
 ### Database Mapping Test
 
-    http://localhost:8080/wicket/hello_db?queries=5
+    http://localhost:8080/wicket/db?queries=5

+ 12 - 31
frameworks/Java/wicket/pom.xml

@@ -20,9 +20,8 @@
 	</licenses>
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<wicket.version>7.1.0</wicket.version>
-		<jetty.version>8.1.18.v20150929</jetty.version>
-		<slf4j.version>1.7.12</slf4j.version>
+		<wicket.version>7.5.0</wicket.version>
+		<slf4j.version>1.7.21</slf4j.version>
 	</properties>
 	<dependencies>
 		<!-- WICKET DEPENDENCIES -->
@@ -36,7 +35,7 @@
 		<dependency>
 			<groupId>com.zaxxer</groupId>
 			<artifactId>HikariCP</artifactId>
-			<version>2.4.3</version>
+			<version>2.5.1</version>
 			<scope>compile</scope>
 		</dependency>
 
@@ -60,24 +59,22 @@
 			<scope>test</scope>
 		</dependency>
 
-		<!-- JETTY DEPENDENCIES FOR TESTING -->
 		<dependency>
-			<groupId>org.eclipse.jetty.aggregate</groupId>
-			<artifactId>jetty-all-server</artifactId>
-			<version>${jetty.version}</version>
-			<scope>provided</scope>
+			<groupId>com.fasterxml.jackson.module</groupId>
+			<artifactId>jackson-module-afterburner</artifactId>
+			<version>2.8.5</version>
 		</dependency>
 
 		<dependency>
 			<groupId>com.fasterxml.jackson.core</groupId>
-			<artifactId>jackson-databind</artifactId>
-			<version>2.7.0</version>
+			<artifactId>jackson-annotations</artifactId>
+			<version>2.8.5</version>
 		</dependency>
 
 		<dependency>
 			<groupId>mysql</groupId>
 			<artifactId>mysql-connector-java</artifactId>
-			<version>5.1.38</version>
+			<version>6.0.5</version>
 		</dependency>
 	</dependencies>
 	<build>
@@ -118,30 +115,14 @@
 				<inherited>true</inherited>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-compiler-plugin</artifactId>
-				<version>3.1</version>
+				<version>3.6.0</version>
 				<configuration>
-					<source>1.7</source>
-					<target>1.7</target>
+					<source>1.8</source>
+					<target>1.8</target>
 					<optimize>true</optimize>
 					<debug>false</debug>
 				</configuration>
 			</plugin>
-			<plugin>
-				<groupId>org.mortbay.jetty</groupId>
-				<artifactId>jetty-maven-plugin</artifactId>
-				<version>${jetty.version}</version>
-				<configuration>
-					<connectors>
-						<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
-							<port>8080</port>
-							<maxIdleTime>3600000</maxIdleTime>
-						</connector>
-						<!--connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector"> 
-							<port>8443</port> <maxIdleTime>3600000</maxIdleTime> <keystore>${project.build.directory}/test-classes/keystore</keystore> 
-							<password>wicket</password> <keyPassword>wicket</keyPassword> </connector -->
-					</connectors>
-				</configuration>
-			</plugin>
 		</plugins>
 	</build>
 

+ 0 - 8
frameworks/Java/wicket/src/main/java/hellowicket/BasePage.html

@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<html xmlns:wicket="http://wicket.apache.org">
-  <head>
-  </head>
-  <body>
-    <wicket:child />
-  </body>
-</html>

+ 0 - 8
frameworks/Java/wicket/src/main/java/hellowicket/BasePage.java

@@ -1,8 +0,0 @@
-package hellowicket;
-
-import org.apache.wicket.markup.html.WebPage;
-
-public class BasePage extends WebPage
-{
-  private static final long serialVersionUID = 1L;
-}

+ 21 - 19
frameworks/Java/wicket/src/main/java/hellowicket/HelloDbResponse.java

@@ -1,27 +1,23 @@
 package hellowicket;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.util.string.StringValue;
+
+import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.concurrent.ThreadLocalRandom;
 
-import javax.sql.DataSource;
-
-import org.apache.wicket.request.resource.AbstractResource;
-import org.apache.wicket.util.string.StringValue;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
 public class HelloDbResponse extends AbstractResource
 {
   private static final long serialVersionUID = 1L;
 
   private static final int DB_ROWS = 10000;
-
-  private static final String CONTENT_TYPE = "application/json";
-  private static final ObjectMapper mapper = new ObjectMapper();
+  private static final String TEXT_PLAIN = "text/plain";
 
   protected ResourceResponse newResourceResponse(Attributes attributes)
   {
@@ -38,29 +34,35 @@ public class HelloDbResponse extends AbstractResource
     final int queries = qs;
 
     final ResourceResponse response = new ResourceResponse();
-    response.setContentType(CONTENT_TYPE);
 
     try
     {
-      final String data = getDataFromDatabase(queriesParam, queries);
+      final byte[] data = getDataFromDatabase(queriesParam, queries);
+      final WebResponse webResponse = (WebResponse) attributes.getResponse();
+      webResponse.setContentLength(data.length);
+      webResponse.setContentType(HelloJsonResponse.APPLICATION_JSON);
       response.setWriteCallback(new WriteCallback()
       {
         public void writeData(Attributes attributes)
         {
-          attributes.getResponse().write(data);
+          webResponse.write(data);
         }
       });
     }
     catch (Exception ex)
     {
-      response.setContentType("text/plain");
+      response.setContentType(TEXT_PLAIN);
       response.setError(500, ex.getClass().getSimpleName() + ": " + ex.getMessage());
       ex.printStackTrace();
     }
     return response;
   }
 
-  private String getDataFromDatabase(final StringValue queriesParam, final int queries)
+  @Override
+  protected void setResponseHeaders(final ResourceResponse resourceResponse, final Attributes attributes) {
+  }
+
+  private byte[] getDataFromDatabase(final StringValue queriesParam, final int queries)
       throws SQLException, JsonProcessingException
   {
     final ThreadLocalRandom random = ThreadLocalRandom.current();
@@ -83,16 +85,16 @@ public class HelloDbResponse extends AbstractResource
       }
     }
 
-    String data;
+    byte[] data;
     if (queriesParam.isNull())
     {
       // request to /db should return JSON object
-      data = HelloDbResponse.mapper.writeValueAsString(worlds[0]);
+      data = HelloJsonResponse.MAPPER.writeValueAsBytes(worlds[0]);
     }
     else
     {
       // request to /db?queries=xyz should return JSON array (issue #648)
-      data = HelloDbResponse.mapper.writeValueAsString(worlds);
+      data = HelloJsonResponse.MAPPER.writeValueAsBytes(worlds);
     }
     return data;
   }

+ 22 - 14
frameworks/Java/wicket/src/main/java/hellowicket/HelloJsonResponse.java

@@ -1,36 +1,39 @@
 package hellowicket;
 
-import java.io.IOException;
-import java.util.Map;
-
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
+import org.apache.wicket.request.http.WebResponse;
 import org.apache.wicket.request.resource.AbstractResource;
-import org.apache.wicket.util.collections.MiniMap;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
 
 public class HelloJsonResponse extends AbstractResource
 {
   private static final long serialVersionUID = 1L;
 
-  private static final String CONTENT_TYPE = "application/json";
-  private static final ObjectMapper mapper = new ObjectMapper();
+  private static final String HELLO_WORLD = "Hello, World!";
+  public static final String APPLICATION_JSON = "application/json";
+  public static final ObjectMapper MAPPER = new ObjectMapper();
+
+  static  {
+    MAPPER.registerModule(new AfterburnerModule());
+  }
 
   protected ResourceResponse newResourceResponse(Attributes attributes)
   {
     final ResourceResponse response = new ResourceResponse();
-    response.setContentLength(27);
-    response.setContentType(CONTENT_TYPE);
     response.setWriteCallback(new WriteCallback()
     {
       public void writeData(Attributes attributes)
       {
-        Map<String, String> data = new MiniMap<>(1);
-        data.put("message", "Hello, World!");
-
         try
         {
-            String json = HelloJsonResponse.mapper.writeValueAsString(data);
-            attributes.getResponse().write(json);
+          final WebResponse webResponse = (WebResponse) attributes.getResponse();
+          webResponse.setContentLength(27);
+          webResponse.setContentType(APPLICATION_JSON);
+          JsonMessage message = new JsonMessage(HELLO_WORLD);
+          byte[] json = MAPPER.writeValueAsBytes(message);
+          webResponse.write(json);
         }
         catch (IOException ex)
         {
@@ -40,4 +43,9 @@ public class HelloJsonResponse extends AbstractResource
     });
     return response;
   }
+
+  @Override
+  protected void setResponseHeaders(final ResourceResponse resourceResponse, final Attributes attributes) {
+
+  }
 }

+ 15 - 0
frameworks/Java/wicket/src/main/java/hellowicket/JsonMessage.java

@@ -0,0 +1,15 @@
+package hellowicket;
+
+public class JsonMessage {
+
+	private final String message;
+
+	public JsonMessage(String message) {
+        super();
+		this.message = message;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+}

+ 50 - 0
frameworks/Java/wicket/src/main/java/hellowicket/RequestMapper.java

@@ -0,0 +1,50 @@
+package hellowicket;
+
+import org.apache.wicket.core.request.handler.PageProvider;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.IRequestMapper;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
+
+import hellowicket.dbupdates.HelloDbUpdatesReference;
+import hellowicket.fortune.FortunePage;
+import hellowicket.plaintext.HelloTextReference;
+
+/**
+ * Custom request mapper optimized for the application needs
+ */
+public class RequestMapper implements IRequestMapper {
+
+    private static final Url FORTUNES_URL = Url.parse("fortunes");
+
+    @Override
+    public IRequestHandler mapRequest(final Request request) {
+        final String url = request.getUrl().toString();
+        switch (url) {
+            case "json":
+                return new ResourceReferenceRequestHandler(new HelloJsonReference());
+            case "db":
+                return new ResourceReferenceRequestHandler(new HelloDbReference());
+            case "updates":
+                return new ResourceReferenceRequestHandler(new HelloDbUpdatesReference());
+            case "plaintext":
+                return new ResourceReferenceRequestHandler(new HelloTextReference());
+            case "fortunes":
+                return new RenderPageRequestHandler(new PageProvider(FortunePage.class));
+            default:
+        }
+        return null;
+    }
+
+    @Override
+    public int getCompatibilityScore(final Request request) {
+        return 0;
+    }
+
+    @Override
+    public Url mapHandler(final IRequestHandler requestHandler) {
+        return FORTUNES_URL;
+    }
+}

+ 7 - 20
frameworks/Java/wicket/src/main/java/hellowicket/WicketApplication.java

@@ -1,16 +1,11 @@
 package hellowicket;
 
-import javax.naming.InitialContext;
-import javax.sql.DataSource;
-
+import com.zaxxer.hikari.HikariDataSource;
 import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.settings.RequestCycleSettings;
 
-import com.zaxxer.hikari.HikariDataSource;
-
-import hellowicket.dbupdates.HelloDbUpdatesReference;
-import hellowicket.fortune.FortunePage;
-import hellowicket.plaintext.HelloTextReference;
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
 
 /**
  * Application object for your web application..
@@ -32,14 +27,6 @@ public class WicketApplication extends WebApplication
 
 		db = newDataSource();
 
-		// mount the resources under test
-		mountResource("/json", new HelloJsonReference());
-		mountResource("/db", new HelloDbReference());
-		mountResource("/updates", new HelloDbUpdatesReference());
-		mountResource("/plaintext", new HelloTextReference());
-
-		mountPage("/fortunes", FortunePage.class);
-
 		// disable response caching to be more close to other
 		// test applications' behavior
 		RequestCycleSettings requestCycleSettings = getRequestCycleSettings();
@@ -47,6 +34,8 @@ public class WicketApplication extends WebApplication
 
 		// set UTF-8 for /fortunes test
 		requestCycleSettings.setResponseRequestEncoding("UTF-8");
+
+		setRootRequestMapper(new RequestMapper());
 	}
 
 	@Override
@@ -78,8 +67,6 @@ public class WicketApplication extends WebApplication
 		DataSource dataSource;
 		try
 		{
-			Class.forName("com.mysql.jdbc.Driver");
-
 			if (useResinDataSource())
 			{
 				InitialContext jndiContext = new InitialContext();
@@ -92,8 +79,8 @@ public class WicketApplication extends WebApplication
 				HikariDataSource ds = new HikariDataSource();
 
 				// use faster DataSource impl
-				ds.setJdbcUrl("jdbc:mysql://localhost: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");
-				ds.setDriverClassName("com.mysql.jdbc.Driver");
+				ds.setJdbcUrl("jdbc:mysql://localhost: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=true&cacheRSMetadata=true&useSSL=false");
+				ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
 				ds.setUsername("benchmarkdbuser");
 				ds.setPassword("benchmarkdbpass");
 				dataSource = ds;

+ 14 - 11
frameworks/Java/wicket/src/main/java/hellowicket/dbupdates/HelloDbUpdatesResource.java

@@ -1,16 +1,15 @@
 package hellowicket.dbupdates;
 
+import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.request.resource.AbstractResource;
+
+import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.util.concurrent.ThreadLocalRandom;
 
-import javax.sql.DataSource;
-
-import org.apache.wicket.request.resource.AbstractResource;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
+import hellowicket.HelloJsonResponse;
 import hellowicket.WicketApplication;
 import hellowicket.World;
 
@@ -24,8 +23,6 @@ public class HelloDbUpdatesResource extends AbstractResource
 
   private static final int DB_ROWS = 10000;
 
-  private static final ObjectMapper mapper = new ObjectMapper();
-
   protected ResourceResponse newResourceResponse(Attributes attributes)
   {
     int _queries = attributes.getRequest().getQueryParameters().getParameterValue("queries").toInt(1);
@@ -40,7 +37,6 @@ public class HelloDbUpdatesResource extends AbstractResource
     final int queries = _queries;
 
     final ResourceResponse response = new ResourceResponse();
-    response.setContentType("application/json");
 
     response.setWriteCallback(new WriteCallback() {
       public void writeData(Attributes attributes)
@@ -78,8 +74,11 @@ public class HelloDbUpdatesResource extends AbstractResource
             }
           }
 
-          String data = HelloDbUpdatesResource.mapper.writeValueAsString(worlds);
-          attributes.getResponse().write(data);
+          byte[] data = HelloJsonResponse.MAPPER.writeValueAsBytes(worlds);
+          final WebResponse webResponse = (WebResponse) attributes.getResponse();
+          webResponse.setContentLength(data.length);
+          webResponse.setContentType(HelloJsonResponse.APPLICATION_JSON);
+          webResponse.write(data);
         }
         catch (Exception ex)
         {
@@ -89,4 +88,8 @@ public class HelloDbUpdatesResource extends AbstractResource
     });
     return response;
   }
+
+  @Override
+  protected void setResponseHeaders(final ResourceResponse resourceResponse, final Attributes attributes) {
+  }
 }

+ 12 - 1
frameworks/Java/wicket/src/main/java/hellowicket/fortune/FortunePage.java

@@ -14,6 +14,7 @@ import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.request.http.WebResponse;
 
 /**
  * A page that loads all fortune cookies. This mimics the Servlet example
@@ -22,6 +23,7 @@ import org.apache.wicket.markup.html.list.ListView;
  */
 public class FortunePage extends WebPage {
 	private static final long serialVersionUID = 1L;
+	private static final String TEXT_HTML = "text/html";
 
 	public FortunePage() throws Exception {
 		List<Fortune> fortunes = new ArrayList<>(10000);
@@ -31,7 +33,7 @@ public class FortunePage extends WebPage {
 				Connection connection = dataSource.getConnection();
 				PreparedStatement statement = connection.prepareStatement("SELECT id, message FROM Fortune",
 						ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-				ResultSet resultSet = statement.executeQuery();) {
+				ResultSet resultSet = statement.executeQuery()) {
 
 			while (resultSet.next()) {
 				fortunes.add(new Fortune(resultSet.getInt("id"), resultSet.getString("message")));
@@ -54,4 +56,13 @@ public class FortunePage extends WebPage {
 		};
 		add(listView);
 	}
+
+	@Override
+	protected void configureResponse(final WebResponse response) {
+		response.setContentType(TEXT_HTML);
+	}
+
+	@Override
+	protected void renderXmlDecl() {
+	}
 }

+ 11 - 5
frameworks/Java/wicket/src/main/java/hellowicket/plaintext/HelloTextResource.java

@@ -1,9 +1,10 @@
 package hellowicket.plaintext;
 
-import java.nio.charset.Charset;
-
+import org.apache.wicket.request.http.WebResponse;
 import org.apache.wicket.request.resource.AbstractResource;
 
+import java.nio.charset.Charset;
+
 /**
  * A resource that implements the requirements for
  * <a href="http://www.techempower.com/benchmarks/#section=code">Test type 6: Plaintext</a>
@@ -18,14 +19,19 @@ public class HelloTextResource extends AbstractResource
   protected ResourceResponse newResourceResponse(Attributes attributes)
   {
     ResourceResponse response = new ResourceResponse();
-    response.setContentType(CONTENT_TYPE);
-    response.setContentLength(DATA.length);
     response.setWriteCallback(new WriteCallback() {
       public void writeData(Attributes attributes)
       {
-        attributes.getResponse().write(DATA);
+        final WebResponse webResponse = (WebResponse) attributes.getResponse();
+        webResponse.setContentType(CONTENT_TYPE);
+        webResponse.setContentLength(DATA.length);
+        webResponse.write(DATA);
       }
     });
     return response;
   }
+
+  @Override
+  protected void setResponseHeaders(final ResourceResponse resourceResponse, final Attributes attributes) {
+  }
 }