You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2016/12/03 19:31:09 UTC

wicket git commit: WICKET-6056 make it easier to gather more properties

Repository: wicket
Updated Branches:
  refs/heads/master 0914576ad -> 81684f93d


WICKET-6056 make it easier to gather more properties


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/81684f93
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/81684f93
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/81684f93

Branch: refs/heads/master
Commit: 81684f93dde752bed5208353a035a524430d08be
Parents: 0914576
Author: Sven Meier <sv...@apache.org>
Authored: Thu Nov 24 16:32:22 2016 +0100
Committer: Sven Meier <sv...@apache.org>
Committed: Sat Dec 3 20:05:07 2016 +0100

----------------------------------------------------------------------
 .../wicket/ajax/AjaxClientInfoBehavior.java     | 47 +++-------------
 .../markup/html/pages/BrowserInfoForm.html      | 16 ------
 .../markup/html/pages/BrowserInfoForm.java      | 47 ++--------------
 .../markup/html/pages/BrowserInfoPage.java      | 43 +++++++++++----
 .../markup/html/pages/wicket-browser-info.js    | 11 +++-
 .../wicket/protocol/http/ClientProperties.java  | 57 +++++++++++++++-----
 .../protocol/http/request/WebClientInfo.java    | 39 ++++++++++++--
 .../ajaxhellobrowser/AjaxHelloBrowser.java      | 36 +++++++++++--
 .../ExtendedClientProperties.java               | 49 +++++++++++++++++
 9 files changed, 214 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxClientInfoBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxClientInfoBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxClientInfoBehavior.java
index 164c551..f51f8a4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxClientInfoBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxClientInfoBehavior.java
@@ -22,7 +22,6 @@ import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.html.pages.BrowserInfoForm;
-import org.apache.wicket.protocol.http.ClientProperties;
 import org.apache.wicket.protocol.http.request.WebClientInfo;
 import org.apache.wicket.request.IRequestParameters;
 import org.apache.wicket.request.cycle.RequestCycle;
@@ -66,50 +65,20 @@ public class AjaxClientInfoBehavior extends AbstractAjaxTimerBehavior
 		stop(target);
 
 		RequestCycle requestCycle = RequestCycle.get();
+
 		IRequestParameters requestParameters = requestCycle.getRequest().getRequestParameters();
-		String navigatorAppName = requestParameters.getParameterValue("navigatorAppName").toString("N/A");
-		String navigatorAppVersion = requestParameters.getParameterValue("navigatorAppVersion").toString("N/A");
-		String navigatorAppCodeName = requestParameters.getParameterValue("navigatorAppCodeName").toString("N/A");
-		boolean navigatorCookieEnabled = requestParameters.getParameterValue("navigatorCookieEnabled").toBoolean(false);
-		Boolean navigatorJavaEnabled = requestParameters.getParameterValue("navigatorJavaEnabled").toBoolean(false);
-		String navigatorLanguage = requestParameters.getParameterValue("navigatorLanguage").toString("N/A");
-		String navigatorPlatform = requestParameters.getParameterValue("navigatorPlatform").toString("N/A");
-		String navigatorUserAgent = requestParameters.getParameterValue("navigatorUserAgent").toString("N/A");
-		int screenWidth = requestParameters.getParameterValue("screenWidth").toInt(-1);
-		int screenHeight = requestParameters.getParameterValue("screenHeight").toInt(-1);
-		int screenColorDepth = requestParameters.getParameterValue("screenColorDepth").toInt(-1);
-		String utcOffset = requestParameters.getParameterValue("utcOffset").toString("N/A");
-		String utcDSTOffset = requestParameters.getParameterValue("utcDSTOffset").toString("N/A");
-		int browserWidth = requestParameters.getParameterValue("browserWidth").toInt(-1);
-		int browserHeight = requestParameters.getParameterValue("browserHeight").toInt(-1);
-		String hostname = requestParameters.getParameterValue("hostname").toString("N/A");
-
-		WebClientInfo clientInfo = new WebClientInfo(requestCycle);
+		WebClientInfo clientInfo = newWebClientInfo(requestCycle);
+		clientInfo.getProperties().read(requestParameters);
 		Session.get().setClientInfo(clientInfo);
 
-		ClientProperties properties = clientInfo.getProperties();
-		properties.setJavaScriptEnabled(true);
-
-		properties.setNavigatorAppCodeName(navigatorAppCodeName);
-		properties.setNavigatorAppName(navigatorAppName);
-		properties.setNavigatorAppVersion(navigatorAppVersion);
-		properties.setNavigatorCookieEnabled(navigatorCookieEnabled);
-		properties.setNavigatorJavaEnabled(navigatorJavaEnabled);
-		properties.setNavigatorLanguage(navigatorLanguage);
-		properties.setNavigatorPlatform(navigatorPlatform);
-		properties.setNavigatorUserAgent(navigatorUserAgent);
-		properties.setScreenWidth(screenWidth);
-		properties.setScreenHeight(screenHeight);
-		properties.setScreenColorDepth(screenColorDepth);
-		properties.setUtcOffset(utcOffset);
-		properties.setUtcDSTOffset(utcDSTOffset);
-		properties.setBrowserWidth(browserWidth);
-		properties.setBrowserHeight(browserHeight);
-		properties.setHostname(hostname);
-
 		onClientInfo(target, clientInfo);
 	}
 
+	protected WebClientInfo newWebClientInfo(RequestCycle requestCycle)
+	{
+		return new WebClientInfo(requestCycle);
+	}
+
 	/**
 	 * A callback method invoked when the client info is collected.
 	 * 

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.html
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.html b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.html
index 5676493..add368f 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.html
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.html
@@ -19,22 +19,6 @@
 <html xmlns:wicket="http://wicket.apache.org">
 	<wicket:panel>
 		<form name="postback" wicket:id="postback" style="position:absolute; left: -10000px;">
-			<input type="text" wicket:id="navigatorAppName" value="test" />
-			<input type="text" wicket:id="navigatorAppVersion" value="test" />
-			<input type="text" wicket:id="navigatorAppCodeName" />
-			<input type="text" wicket:id="navigatorCookieEnabled" />
-			<input type="text" wicket:id="navigatorJavaEnabled" />
-			<input type="text" wicket:id="navigatorLanguage" />
-			<input type="text" wicket:id="navigatorPlatform" />
-			<input type="text" wicket:id="navigatorUserAgent" />
-			<input type="text" wicket:id="screenWidth" />
-			<input type="text" wicket:id="screenHeight" />
-			<input type="text" wicket:id="screenColorDepth" />
-			<input type="text" wicket:id="utcOffset" />
-			<input type="text" wicket:id="utcDSTOffset" />
-			<input type="text" wicket:id="browserWidth" />
-			<input type="text" wicket:id="browserHeight" />
-			<input type="text" wicket:id="hostname" />
 		</form>
 	</wicket:panel>
 </html>

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.java
index 8164c1b..51ef702 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoForm.java
@@ -16,14 +16,10 @@
  */
 package org.apache.wicket.markup.html.pages;
 
-import java.util.Locale;
-
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.panel.GenericPanel;
-import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.protocol.http.ClientProperties;
 import org.apache.wicket.request.resource.JavaScriptResourceReference;
@@ -67,33 +63,18 @@ public class BrowserInfoForm extends GenericPanel<ClientProperties>
 	 */
 	protected Form<ClientProperties> createForm(String componentId, IModel<ClientProperties> properties)
 	{
-		Form<ClientProperties> form = new Form<ClientProperties>(componentId,
-				new CompoundPropertyModel<ClientProperties>(properties))
+		Form<ClientProperties> form = new Form<ClientProperties>(componentId, properties)
 		{
 			private static final long serialVersionUID = 1L;
 
 			@Override
 			protected void onSubmit()
 			{
+				getModelObject().read(getRequest().getPostParameters());
+
 				afterSubmit();
 			}
 		};
-		form.add(new ReadOnlyTextField<String>("navigatorAppName"));
-		form.add(new ReadOnlyTextField<String>("navigatorAppVersion"));
-		form.add(new ReadOnlyTextField<String>("navigatorAppCodeName"));
-		form.add(new ReadOnlyTextField<Boolean>("navigatorCookieEnabled"));
-		form.add(new ReadOnlyTextField<Boolean>("navigatorJavaEnabled"));
-		form.add(new ReadOnlyTextField<String>("navigatorLanguage"));
-		form.add(new ReadOnlyTextField<String>("navigatorPlatform"));
-		form.add(new ReadOnlyTextField<String>("navigatorUserAgent"));
-		form.add(new ReadOnlyTextField<String>("screenWidth"));
-		form.add(new ReadOnlyTextField<String>("screenHeight"));
-		form.add(new ReadOnlyTextField<String>("screenColorDepth"));
-		form.add(new ReadOnlyTextField<String>("utcOffset"));
-		form.add(new ReadOnlyTextField<String>("utcDSTOffset"));
-		form.add(new ReadOnlyTextField<String>("browserWidth"));
-		form.add(new ReadOnlyTextField<String>("browserHeight"));
-		form.add(new ReadOnlyTextField<String>("hostname"));
 		return form;
 	}
 
@@ -116,24 +97,4 @@ public class BrowserInfoForm extends GenericPanel<ClientProperties>
 	{
 		return form.getMarkupId();
 	}
-	
-	private static final class ReadOnlyTextField<T> extends TextField<T> {
-
-		public ReadOnlyTextField(String id)
-		{
-			super(id);
-		}
-
-		@Override
-		protected String getModelValue()
-		{
-			return "";
-		}
-		
-		@Override
-		public Locale getLocale()
-		{
-			return Locale.ENGLISH;
-		}
-	}
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoPage.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoPage.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoPage.java
index e7143d7..8d2cdc8 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoPage.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/BrowserInfoPage.java
@@ -22,8 +22,11 @@ import org.apache.wicket.markup.head.OnLoadHeaderItem;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.protocol.http.ClientProperties;
 import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.protocol.http.request.WebClientInfo;
+import org.apache.wicket.request.cycle.RequestCycle;
 
 /**
  * This page uses a form post right after the page has loaded in the browser, using JavaScript or
@@ -46,7 +49,7 @@ public class BrowserInfoPage extends WebPage
 	private static final long serialVersionUID = 1L;
 
 	private BrowserInfoForm browserInfoForm;
-
+	
 	/**
 	 * Bookmarkable constructor.
 	 */
@@ -70,21 +73,34 @@ public class BrowserInfoPage extends WebPage
 		return false;
 	}
 
+	protected WebClientInfo newWebClientInfo(RequestCycle requestCycle)
+	{
+		return new WebClientInfo(requestCycle);
+	}
+
 	/**
 	 * Adds components.
 	 */
 	private void initComps()
 	{
-		IModel<ClientProperties> properties = new IModel<ClientProperties>()
+		IModel<WebClientInfo> info = new LoadableDetachableModel<WebClientInfo>() {
+			@Override
+			protected WebClientInfo load()
+			{
+				return newWebClientInfo(getRequestCycle());
+			}			
+		};
+
+		IModel<ClientProperties> properties = new LoadableDetachableModel<ClientProperties>()
 		{
 			@Override
-			public ClientProperties getObject()
+			protected ClientProperties load()
 			{
-				return WebSession.get().getClientInfo().getProperties();
+				return info.getObject().getProperties();
 			}
 		};
 
-		add(new ContinueLink("link", properties));
+		add(new ContinueLink("link", info));
 
 		browserInfoForm = new BrowserInfoForm("postback", properties)
 		{
@@ -95,6 +111,8 @@ public class BrowserInfoPage extends WebPage
 			{
 				getModelObject().setJavaScriptEnabled(true);
 
+				WebSession.get().setClientInfo(info.getObject());
+
 				continueToOriginalDestination();
 
 				// switch to home page if no original destination was intercepted
@@ -104,11 +122,16 @@ public class BrowserInfoPage extends WebPage
 		add(browserInfoForm);
 	}
 	
-	private static class ContinueLink extends Link<ClientProperties> {
+	protected ClientProperties newClientInfo()
+	{
+		return WebSession.get().getClientInfo().getProperties();
+	}
+
+	private static class ContinueLink extends Link<WebClientInfo> {
 
-		public ContinueLink(String id, IModel<ClientProperties> properties)
+		public ContinueLink(String id, IModel<WebClientInfo> info)
 		{
-			super(id, properties);
+			super(id, info);
 		}
 
 		@Override
@@ -122,7 +145,9 @@ public class BrowserInfoPage extends WebPage
 		@Override
 		public void onClick()
 		{
-			getModelObject().setJavaScriptEnabled(false);
+			getModelObject().getProperties().setJavaScriptEnabled(false);
+
+			WebSession.get().setClientInfo(getModelObject());
 
 			continueToOriginalDestination();
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/wicket-browser-info.js
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/wicket-browser-info.js b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/wicket-browser-info.js
index 0d524af..cd0da94 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/wicket-browser-info.js
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/pages/wicket-browser-info.js
@@ -63,6 +63,11 @@
 				info.browserWidth =  window.innerWidth || document.body.offsetWidth;
 				info.browserHeight =  window.innerHeight || document.body.offsetHeight;
 				info.hostname =  window.location.hostname;
+
+				if (Wicket.BrowserInfo.collectExtraInfo) {
+					Wicket.BrowserInfo.collectExtraInfo(info);
+				}
+
 				return info;
 			},
 
@@ -77,7 +82,11 @@
 				var info = Wicket.BrowserInfo.collect();
 				var i;
 				for (i in info) {
-					postbackForm[i].value = info[i];
+					var input = document.createElement('input');
+					input.type = 'text';
+					input.name = i;
+					input.value = info[i];
+					postbackForm.appendChild(input);
 				}
 
 				return postbackForm;

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/protocol/http/ClientProperties.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/ClientProperties.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/ClientProperties.java
index b566708..cd97e4f 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/ClientProperties.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/ClientProperties.java
@@ -17,12 +17,14 @@
 package org.apache.wicket.protocol.http;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.util.Collection;
 import java.util.TimeZone;
 
 import javax.servlet.http.Cookie;
 
 import org.apache.wicket.markup.html.pages.BrowserInfoPage;
+import org.apache.wicket.request.IRequestParameters;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.http.WebRequest;
 import org.apache.wicket.util.io.IClusterable;
@@ -77,16 +79,15 @@ public class ClientProperties implements IClusterable
 	private int screenColorDepth = -1;
 	private int screenHeight = -1;
 	private int screenWidth = -1;
-	/** Cached timezone for repeating calls to {@link #getTimeZone()} */
-	private TimeZone timeZone;
 	private String utcDSTOffset;
-
 	private String utcOffset;
-
 	private String hostname;
 
 	private boolean javaScriptEnabled;
 
+	/** Cached timezone for repeating calls to {@link #getTimeZone()} */
+	private transient TimeZone timeZone;
+
 	/**
 	 * @return The browser height at the time it was measured
 	 */
@@ -730,15 +731,19 @@ public class ClientProperties implements IClusterable
 	{
 		StringBuilder b = new StringBuilder();
 
-		Field[] fields = ClientProperties.class.getDeclaredFields();
+		Class<?> clazz = getClass();
+		while (clazz != Object.class) {
+			Field[] fields = clazz.getDeclaredFields();
 
-		for (Field field : fields)
-		{
-			// Ignore these fields
-			if (field.getName().equals("serialVersionUID") == false &&
-				field.getName().startsWith("class$") == false &&
-				field.getName().startsWith("timeZone") == false)
+			for (Field field : fields)
 			{
+				// Ignore these fields
+				if (Modifier.isStatic(field.getModifiers()) ||
+					Modifier.isTransient(field.getModifiers())  ||
+					field.isSynthetic())
+				{
+					continue;
+				}
 
 				field.setAccessible(true);
 
@@ -772,9 +777,35 @@ public class ClientProperties implements IClusterable
 					b.append('\n');
 				}
 			}
-		}
 
+			clazz = clazz.getSuperclass();
+		}
 		return b.toString();
 	}
 
-}
+	/**
+	 * Read parameters.
+	 * 
+	 * @param parameters
+	 *            parameters sent from browser
+	 */
+	public void read(IRequestParameters parameters)
+	{
+		setNavigatorAppCodeName(parameters.getParameterValue("navigatorAppCodeName").toString("N/A"));
+		setNavigatorAppName(parameters.getParameterValue("navigatorAppName").toString("N/A"));
+		setNavigatorAppVersion(parameters.getParameterValue("navigatorAppVersion").toString("N/A"));
+		setNavigatorCookieEnabled(parameters.getParameterValue("navigatorCookieEnabled").toBoolean(false));
+		setNavigatorJavaEnabled(parameters.getParameterValue("navigatorJavaEnabled").toBoolean(false));
+		setNavigatorLanguage(parameters.getParameterValue("navigatorLanguage").toString("N/A"));
+		setNavigatorPlatform(parameters.getParameterValue("navigatorPlatform").toString("N/A"));
+		setNavigatorUserAgent(parameters.getParameterValue("navigatorUserAgent").toString("N/A"));
+		setScreenWidth(parameters.getParameterValue("screenWidth").toInt(-1));
+		setScreenHeight(parameters.getParameterValue("screenHeight").toInt(-1));
+		setScreenColorDepth(parameters.getParameterValue("screenColorDepth").toInt(-1));
+		setUtcOffset(parameters.getParameterValue("utcOffset").toString(null));
+		setUtcDSTOffset(parameters.getParameterValue("utcDSTOffset").toString(null));
+		setBrowserWidth(parameters.getParameterValue("browserWidth").toInt(-1));
+		setBrowserHeight(parameters.getParameterValue("browserHeight").toInt(-1));
+		setHostname(parameters.getParameterValue("hostname").toString("N/A"));
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-core/src/main/java/org/apache/wicket/protocol/http/request/WebClientInfo.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/request/WebClientInfo.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/request/WebClientInfo.java
index 9fc4700..2b0747c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/request/WebClientInfo.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/request/WebClientInfo.java
@@ -52,7 +52,7 @@ public class WebClientInfo extends ClientInfo
 	private final String userAgent;
 
 	/** Client properties object. */
-	private final ClientProperties properties = new ClientProperties();
+	private final ClientProperties properties;
 
 	/**
 	 * Construct.
@@ -62,8 +62,19 @@ public class WebClientInfo extends ClientInfo
 	 */
 	public WebClientInfo(RequestCycle requestCycle)
 	{
+		this(requestCycle, new ClientProperties());
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param requestCycle
+	 *            the request cycle
+	 */
+	public WebClientInfo(RequestCycle requestCycle, ClientProperties properties)
+	{
 		this(requestCycle, ((ServletWebRequest)requestCycle.getRequest()).getContainerRequest()
-			.getHeader("User-Agent"));
+			.getHeader("User-Agent"), properties);
 	}
 
 	/**
@@ -76,10 +87,28 @@ public class WebClientInfo extends ClientInfo
 	 */
 	public WebClientInfo(final RequestCycle requestCycle, final String userAgent)
 	{
+		this(requestCycle, userAgent, new ClientProperties());
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param requestCycle
+	 *            the request cycle
+	 * @param userAgent
+	 *            The User-Agent string
+	 * @param properties
+	 *			  properties of client            
+	 */
+	public WebClientInfo(final RequestCycle requestCycle, final String userAgent, final ClientProperties properties)
+	{
 		super();
 
 		this.userAgent = userAgent;
+
+		this.properties = properties;
 		properties.setRemoteAddress(getRemoteAddr(requestCycle));
+
 		init();
 	}
 
@@ -219,8 +248,8 @@ public class WebClientInfo extends ClientInfo
 
 			if (userAgent.contains("version/"))
 			{
-				// e.g.: Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE) AppleWebKit/533.19.4
-// (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4
+				// e.g.: Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE) AppleWebKit/533.19
+				// (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4
 				setMajorMinorVersionByPattern("version/(\\d+)\\.(\\d+)");
 			}
 		}
@@ -239,7 +268,7 @@ public class WebClientInfo extends ClientInfo
 			if (properties.isBrowserMozillaFirefox())
 			{
 				// e.g.: Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.2) Gecko/20121223
-// Ubuntu/9.25 (jaunty) Firefox/3.8
+				// Ubuntu/9.25 (jaunty) Firefox/3.8
 				setMajorMinorVersionByPattern("firefox/(\\d+)\\.(\\d+)");
 			}
 		}

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/AjaxHelloBrowser.java
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/AjaxHelloBrowser.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/AjaxHelloBrowser.java
index f63f9cd..8a44d21 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/AjaxHelloBrowser.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/AjaxHelloBrowser.java
@@ -21,14 +21,18 @@ import java.util.Calendar;
 import java.util.Locale;
 import java.util.TimeZone;
 
+import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxClientInfoBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.examples.WicketExamplePage;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.basic.MultiLineLabel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.protocol.http.ClientProperties;
 import org.apache.wicket.protocol.http.request.WebClientInfo;
+import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.settings.RequestCycleSettings;
 
 
@@ -78,11 +82,33 @@ public class AjaxHelloBrowser extends WicketExamplePage
 		clientTime.setOutputMarkupPlaceholderTag(true);
 		clientTime.setVisible(false);
 
-		add(AjaxClientInfoBehavior.onClientInfo((AjaxRequestTarget target, WebClientInfo info) -> {
-			clientInfo.setVisible(true);
-			clientTime.setVisible(true);
-			target.add(clientInfo, clientTime);
-		}));
+		add(new AjaxClientInfoBehavior() {
+
+			@Override
+			public void renderHead(Component component, IHeaderResponse response)
+			{
+				super.renderHead(component, response);
+
+				String script = "Wicket.BrowserInfo.collectExtraInfo = function(info) { info.extendedProperty = 'This property was read extra.'; };";
+
+				response.render(JavaScriptHeaderItem.forScript(script, "extended-client-info"));
+			}
+
+			@Override
+			protected WebClientInfo newWebClientInfo(RequestCycle requestCycle)
+			{
+				return new WebClientInfo(requestCycle, new ExtendedClientProperties());
+			}
+
+			@Override
+			protected void onClientInfo(AjaxRequestTarget target, WebClientInfo webClientInfo)
+			{
+				clientInfo.setVisible(true);
+				clientTime.setVisible(true);
+
+				target.add(clientInfo, clientTime);
+			}
+		});
 
 		add(clientInfo, clientTime);
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/81684f93/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/ExtendedClientProperties.java
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/ExtendedClientProperties.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/ExtendedClientProperties.java
new file mode 100644
index 0000000..1d301f3
--- /dev/null
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajaxhellobrowser/ExtendedClientProperties.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.examples.ajaxhellobrowser;
+
+import org.apache.wicket.protocol.http.ClientProperties;
+import org.apache.wicket.request.IRequestParameters;
+
+/**
+ * Showcase for extended properties of a client.
+ */
+public class ExtendedClientProperties extends ClientProperties
+{
+	private String extendedProperty;
+	
+	public String getExtendedProperty()
+	{
+		return extendedProperty;
+	}
+
+	public void setExtendedProperty(String extendedProperty)
+	{
+		this.extendedProperty = extendedProperty;
+	}
+
+	/**
+	 * Overridden to read additional properties.
+	 */
+	@Override
+	public void read(IRequestParameters parameters)
+	{
+		super.read(parameters);
+		
+		setExtendedProperty(parameters.getParameterValue("extendedProperty").toString("N/A"));
+	}
+}
\ No newline at end of file