You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by eh...@apache.org on 2006/10/11 01:16:12 UTC

svn commit: r462634 - in /incubator/wicket/branches/wicket-1.x/wicket-threadtest: ./ src/main/java/wicket/threadtest/ src/main/java/wicket/threadtest/apps/ src/main/java/wicket/threadtest/apps/app1/ src/main/java/wicket/threadtest/apps/app2/ src/main/j...

Author: ehillenius
Date: Tue Oct 10 16:16:10 2006
New Revision: 462634

URL: http://svn.apache.org/viewvc?view=rev&rev=462634
Log:
there we go, the working deadlock test

Added:
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test1.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test2.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App2Test1.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Contact.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactDataProvider.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactGenerator.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactsDatabase.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DatabaseLocator.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DetachableContactModel.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/FormInputModel.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home$ActionPanel.html
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.html
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.properties
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/TestApp1.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/UsPhoneNumber.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Connection.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.html
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Pool.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestApp2.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestFilter.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractCommand.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractGetCommand.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Command.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/CommandRunner.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/SimpleGetCommand.java
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Tester.java
Modified:
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/.classpath
    incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/webapp/WEB-INF/web.xml

Modified: incubator/wicket/branches/wicket-1.x/wicket-threadtest/.classpath
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/.classpath?view=diff&rev=462634&r1=462633&r2=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/.classpath (original)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/.classpath Tue Oct 10 16:16:10 2006
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" path="src/java"/>
+	<classpathentry kind="src" path="src/main/java"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="var" path="M2_REPO/jetty/jetty-util/6.0.1/jetty-util-6.0.1.jar"/>
 	<classpathentry kind="var" path="M2_REPO/junit/junit/3.8.1/junit-3.8.1.jar" sourcepath="M2_REPO/junit/junit/3.8.1/junit-3.8.1-sources.jar"/>
@@ -22,7 +22,7 @@
 	<classpathentry kind="var" path="M2_REPO/javax/portlet/portlet-api/1.0/portlet-api-1.0.jar"/>
 	<classpathentry kind="var" path="M2_REPO/commons-httpclient/commons-httpclient/3.0.1/commons-httpclient-3.0.1.jar" sourcepath="M2_REPO/commons-httpclient/commons-httpclient/3.0.1/commons-httpclient-3.0.1-sources.jar"/>
 	<classpathentry kind="var" path="M2_REPO/xerces/xmlParserAPIs/2.2.1/xmlParserAPIs-2.2.1.jar"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/wicket-1.2"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/wicket-extensions-1.2"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/wicket"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/wicket-extensions"/>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test1.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test1.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test1.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test1.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,37 @@
+package wicket.threadtest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import wicket.threadtest.tester.SimpleGetCommand;
+import wicket.threadtest.tester.Tester;
+
+/**
+ * @author eelcohillenius
+ */
+public class App1Test1 {
+
+	private static final Log log = LogFactory.getLog(App1Test1.class);
+
+	/**
+	 * @param args
+	 * @throws Exception
+	 */
+	public static void main(String[] args) throws Exception {
+
+		List<String> gets = Arrays.asList(new String[] {
+				"/app1?wicket:bookmarkablePage=one:wicket.threadtest.apps.app1.Home",
+				"/app1?wicket:bookmarkablePage=two:wicket.threadtest.apps.app1.Home",
+				"/app1?wicket:interface=two:${iteration}:link::ILinkListener",
+				"/app1?wicket:interface=one:${iteration}:link::ILinkListener",
+				"/app1?wicket:interface=two:${iteration}:link::ILinkListener" });
+
+		SimpleGetCommand getCmd = new SimpleGetCommand(gets, 1);
+		//getCmd.setPrintResponse(true);
+		Tester tester = new Tester(getCmd, 50, true);
+		tester.run();
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test2.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test2.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test2.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App1Test2.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,34 @@
+package wicket.threadtest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import wicket.threadtest.tester.SimpleGetCommand;
+import wicket.threadtest.tester.Tester;
+
+/**
+ * @author eelcohillenius
+ */
+public class App1Test2 {
+
+	private static final Log log = LogFactory.getLog(App1Test2.class);
+
+	/**
+	 * @param args
+	 * @throws Exception
+	 */
+	public static void main(String[] args) throws Exception {
+
+		List<String> gets = Arrays
+				.asList(new String[] { "/app1?wicket:bookmarkablePage=one:wicket.threadtest.apps.app1.Home" });
+
+		SimpleGetCommand getCmd = new SimpleGetCommand(gets, 5);
+
+		// getCmd.setPrintResponse(true);
+		Tester tester = new Tester(getCmd, 100, false);
+		tester.run();
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App2Test1.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App2Test1.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App2Test1.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/App2Test1.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,40 @@
+package wicket.threadtest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import wicket.threadtest.tester.SimpleGetCommand;
+import wicket.threadtest.tester.Tester;
+
+/**
+ * @author eelcohillenius
+ */
+public class App2Test1 {
+
+	private static final Log log = LogFactory.getLog(App2Test1.class);
+
+	/**
+	 * @param args
+	 * @throws Exception
+	 */
+	public static void main(String[] args) throws Exception {
+
+		List<String> gets = Arrays
+				.asList(new String[] { "/app2?wicket:bookmarkablePage=one:wicket.threadtest.apps.app2.Home" });
+
+		SimpleGetCommand getCmd = new SimpleGetCommand(gets, 5);
+
+		// getCmd.setPrintResponse(true);
+		
+		// AS OF OCTOBER 9 2006, THIS TYPICALLY RESULTS IN A DEADLOCK
+		Tester tester = new Tester(getCmd, 50, false);
+		
+		// new Tester(.., .., false) would not give a deadlock, as then
+		// all threads point to seperate sessions
+		
+		tester.run();
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Contact.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Contact.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Contact.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Contact.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,157 @@
+/*
+ * $Id: Contact.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $ $Revision: 5394 $
+ * $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import java.io.Serializable;
+
+/**
+ * domain object for demonstrations.
+ * 
+ * @author igor
+ * 
+ */
+public class Contact implements Serializable {
+	private String cellPhone;
+
+	private String firstName;
+
+	private String homePhone;
+
+	private long id;
+
+	private String lastName;
+
+	/**
+	 * Constructor
+	 */
+	public Contact() {
+
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param firstName
+	 * @param lastName
+	 */
+	public Contact(String firstName, String lastName) {
+		this.firstName = firstName;
+		this.lastName = lastName;
+	}
+
+	/**
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (obj == null) {
+			return false;
+		}
+		if (obj instanceof Contact) {
+			Contact other = (Contact) obj;
+			return other.getFirstName().equals(getFirstName()) && other.getLastName().equals(getLastName())
+					&& other.getHomePhone().equals(getHomePhone()) && other.getCellPhone().equals(getCellPhone());
+
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * @return cellPhone
+	 */
+	public String getCellPhone() {
+		return cellPhone;
+	}
+
+	/**
+	 * @return firstName
+	 */
+	public String getFirstName() {
+		return firstName;
+	}
+
+	/**
+	 * @return homePhone
+	 */
+	public String getHomePhone() {
+		return homePhone;
+	}
+
+	/**
+	 * @return id
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @return lastName
+	 */
+	public String getLastName() {
+		return lastName;
+	}
+
+	/**
+	 * @param cellPhone
+	 */
+	public void setCellPhone(String cellPhone) {
+		this.cellPhone = cellPhone;
+	}
+
+	/**
+	 * @param firstName
+	 */
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+
+	/**
+	 * @param homePhone
+	 */
+	public void setHomePhone(String homePhone) {
+		this.homePhone = homePhone;
+	}
+
+	/**
+	 * @param id
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	/**
+	 * @param lastName
+	 */
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return "[Contact id=" + id + " firstName=" + firstName + " lastName=" + lastName + " homePhone=" + homePhone
+				+ " cellPhone=" + cellPhone + "]";
+	}
+
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactDataProvider.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactDataProvider.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactDataProvider.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactDataProvider.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,69 @@
+/*
+ * $Id: ContactDataProvider.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $
+ * $Revision: 5394 $ $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import java.util.Iterator;
+
+import wicket.extensions.markup.html.repeater.data.IDataProvider;
+import wicket.model.IModel;
+
+/**
+ * Implementation of IDataProvider that retrieves contacts from the contact
+ * database.
+ * 
+ * @see wicket.extensions.markup.html.repeater.data.IDataProvider
+ * @see wicket.extensions.markup.html.repeater.data.DataViewBase
+ * 
+ * @author igor
+ * 
+ */
+public class ContactDataProvider implements IDataProvider {
+	/**
+	 * retrieves contacts from database starting with index <code>first</code>
+	 * and ending with <code>first+count</code>
+	 * 
+	 * @see wicket.extensions.markup.html.repeater.data.IDataProvider#iterator(int,
+	 *      int)
+	 */
+	public Iterator iterator(int first, int count) {
+		return getContactsDB().find(first, count, "firstName", true).iterator();
+	}
+
+	/**
+	 * wraps retrieved contact pojo with a wicket model
+	 * 
+	 * @see wicket.extensions.markup.html.repeater.data.IDataProvider#model(java.lang.Object)
+	 */
+	public IModel model(Object object) {
+		return new DetachableContactModel((Contact) object);
+	}
+
+	/**
+	 * returns total number of contacts in the database
+	 * 
+	 * @see wicket.extensions.markup.html.repeater.data.IDataProvider#size()
+	 */
+	public int size() {
+		return getContactsDB().getCount();
+	}
+
+	protected ContactsDatabase getContactsDB() {
+		return DatabaseLocator.getDatabase();
+	}
+
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactGenerator.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactGenerator.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactGenerator.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactGenerator.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,98 @@
+/*
+ * $Id: ContactGenerator.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $ $Revision:
+ * 3056 $ $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import java.util.Collection;
+
+/**
+ * generates random contacts
+ * 
+ * @author igor
+ * 
+ */
+public class ContactGenerator {
+	private static ContactGenerator instance = new ContactGenerator();
+
+	private static long nextId = 1;
+
+	/**
+	 * @return static instance of generator
+	 */
+	public static ContactGenerator getInstance() {
+		return instance;
+	}
+
+	private String[] firstNames = { "Jacob", "Emily", "Michael", "Sarah", "Matthew", "Brianna", "Nicholas", "Samantha",
+			"Christopher", "Hailey", "Abner", "Abby", "Joshua", "Douglas", "Jack", "Keith", "Gerald", "Samuel",
+			"Willie", "Larry", "Jose", "Timothy", "Sandra", "Kathleen", "Pamela", "Virginia", "Debra", "Maria", "Linda" };
+
+	private String[] lastNames = { "Smiith", "Johnson", "Williams", "Jones", "Brown", "Donahue", "Bailey", "Rose",
+			"Allen", "Black", "Davis", "Clark", "Hall", "Lee", "Baker", "Gonzalez", "Nelson", "Moore", "Wilson",
+			"Graham", "Fisher", "Cruz", "Ortiz", "Gomez", "Murray" };
+
+	private ContactGenerator() {
+
+	}
+
+	/**
+	 * generates a new contact
+	 * 
+	 * @return generated contact
+	 */
+	public Contact generate() {
+		Contact contact = new Contact(randomString(firstNames), randomString(lastNames));
+		contact.setId(generateId());
+		contact.setHomePhone(generatePhoneNumber());
+		contact.setCellPhone(generatePhoneNumber());
+		return contact;
+	}
+
+	/**
+	 * generats <code>count</code> number contacts and puts them into
+	 * <code>collection</code> collection
+	 * 
+	 * @param collection
+	 * @param count
+	 */
+	public void generate(Collection<Contact> collection, int count) {
+		for (int i = 0; i < count; i++) {
+			collection.add(generate());
+		}
+	}
+
+	/**
+	 * @return unique id
+	 */
+	public synchronized long generateId() {
+		return nextId++;
+	}
+
+	private String generatePhoneNumber() {
+		return new StringBuffer().append(rint(2, 9)).append(rint(0, 9)).append(rint(0, 9)).append("-555-").append(
+				rint(1, 9)).append(rint(0, 9)).append(rint(0, 9)).append(rint(0, 9)).toString();
+	}
+
+	private String randomString(String[] choices) {
+		return choices[rint(0, choices.length)];
+	}
+
+	private int rint(int min, int max) {
+		return (int) (Math.random() * (max - min) + min);
+	}
+
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactsDatabase.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactsDatabase.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactsDatabase.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/ContactsDatabase.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,171 @@
+/*
+ * $Id: ContactsDatabase.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $ $Revision:
+ * 4619 $ $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * simple database for contacts
+ * 
+ * @author igor
+ * 
+ */
+public class ContactsDatabase {
+
+	private List<Contact> fnameDescIdx = Collections.synchronizedList(new ArrayList<Contact>());
+
+	private List<Contact> fnameIdx = Collections.synchronizedList(new ArrayList<Contact>());
+
+	private List<Contact> lnameDescIdx = Collections.synchronizedList(new ArrayList<Contact>());
+
+	private List<Contact> lnameIdx = Collections.synchronizedList(new ArrayList<Contact>());
+
+	private Map<Long, Contact> map = Collections.synchronizedMap(new HashMap<Long, Contact>());
+
+	/**
+	 * Constructor
+	 * 
+	 * @param count
+	 *            number of contacts to generate at startup
+	 */
+	public ContactsDatabase(int count) {
+		for (int i = 0; i < count; i++) {
+			add(ContactGenerator.getInstance().generate());
+		}
+		updateIndecies();
+	}
+
+	/**
+	 * delete contact from the database
+	 * 
+	 * @param contact
+	 */
+	public void delete(final Contact contact) {
+		Contact c = (Contact) map.remove(new Long(contact.getId()));
+
+		fnameIdx.remove(contact);
+		lnameIdx.remove(contact);
+		fnameDescIdx.remove(contact);
+		lnameDescIdx.remove(contact);
+
+		contact.setId(0);
+	}
+
+	/**
+	 * select contacts and apply sort
+	 * 
+	 * @param first
+	 * @param count
+	 * @param sortProperty
+	 * @param sortAsc
+	 * @return list of contacts
+	 */
+	public List find(int first, int count, String sortProperty, boolean sortAsc) {
+		List sublist = getIndex(sortProperty, sortAsc).subList(first, first + count);
+		return sublist;
+	}
+
+	/**
+	 * find contact by id
+	 * 
+	 * @param id
+	 * @return contact
+	 */
+	public Contact get(long id) {
+		Contact c = (Contact) map.get(new Long(id));
+		if (c == null) {
+			throw new RuntimeException("contact with id [" + id + "] not found in the database");
+		}
+		return c;
+	}
+
+	/**
+	 * @return number of contacts in the database
+	 */
+	public int getCount() {
+		return fnameIdx.size();
+	}
+
+	/**
+	 * add contact to the database
+	 * 
+	 * @param contact
+	 */
+	public void save(final Contact contact) {
+		if (contact.getId() == 0) {
+			contact.setId(ContactGenerator.getInstance().generateId());
+			add(contact);
+			updateIndecies();
+		} else {
+			throw new IllegalArgumentException("contact [" + contact.getFirstName() + "] is already persistent");
+		}
+	}
+
+	protected void add(final Contact contact) {
+		map.put(new Long(contact.getId()), contact);
+		fnameIdx.add(contact);
+		lnameIdx.add(contact);
+		fnameDescIdx.add(contact);
+		lnameDescIdx.add(contact);
+	}
+
+	protected List getIndex(String prop, boolean asc) {
+		if (prop == null) {
+			return fnameIdx;
+		}
+		if (prop.equals("firstName")) {
+			return (asc) ? fnameIdx : fnameDescIdx;
+		} else if (prop.equals("lastName")) {
+			return (asc) ? lnameIdx : lnameDescIdx;
+		}
+		throw new RuntimeException("uknown sort option [" + prop + "]. valid options: [firstName] , [lastName]");
+	}
+
+	private void updateIndecies() {
+		Collections.sort(fnameIdx, new Comparator<Contact>() {
+			public int compare(Contact arg0, Contact arg1) {
+				return arg0.getFirstName().compareTo(arg1.getFirstName());
+			}
+		});
+
+		Collections.sort(lnameIdx, new Comparator<Contact>() {
+			public int compare(Contact arg0, Contact arg1) {
+				return arg0.getLastName().compareTo(arg1.getLastName());
+			}
+		});
+
+		Collections.sort(fnameDescIdx, new Comparator<Contact>() {
+			public int compare(Contact arg0, Contact arg1) {
+				return arg1.getFirstName().compareTo(arg0.getFirstName());
+			}
+		});
+
+		Collections.sort(lnameDescIdx, new Comparator<Contact>() {
+			public int compare(Contact arg0, Contact arg1) {
+				return arg1.getLastName().compareTo(arg0.getLastName());
+			}
+		});
+
+	}
+
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DatabaseLocator.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DatabaseLocator.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DatabaseLocator.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DatabaseLocator.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,33 @@
+/*
+ * $Id: DatabaseLocator.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $ $Revision:
+ * 3056 $ $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+/**
+ * service locator class for contacts database
+ * 
+ * @author igor
+ * 
+ */
+public class DatabaseLocator {
+	/**
+	 * @return contacts database
+	 */
+	public static ContactsDatabase getDatabase() {
+		return TestApp1.get().getContactsDB();
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DetachableContactModel.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DetachableContactModel.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DetachableContactModel.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/DetachableContactModel.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,106 @@
+/*
+ * $Id: DetachableContactModel.java 5394 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) jdonnerstag $
+ * $Revision: 5394 $ $Date: 2006-04-16 06:36:52 -0700 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import wicket.Component;
+import wicket.extensions.markup.html.repeater.refreshing.IItemReuseStrategy;
+import wicket.model.AbstractReadOnlyDetachableModel;
+import wicket.model.IModel;
+
+/**
+ * detachable model for an instance of contact
+ * 
+ * @author igor
+ * 
+ */
+public class DetachableContactModel extends AbstractReadOnlyDetachableModel {
+	private transient Contact contact;
+
+	private long id;
+
+	/**
+	 * @param c
+	 */
+	public DetachableContactModel(Contact c) {
+		this(c.getId());
+		contact = c;
+	}
+
+	/**
+	 * @param id
+	 */
+	public DetachableContactModel(long id) {
+		if (id == 0) {
+			throw new IllegalArgumentException();
+		}
+		this.id = id;
+	}
+
+	/**
+	 * used for dataview with ReuseIfModelsEqualStrategy item reuse strategy
+	 * 
+	 * @see wicket.extensions.markup.html.repeater.pageable.AbstractPageableView#setItemReuseStrategy(IItemReuseStrategy)
+	 * @see wicket.extensions.markup.html.repeater.refreshing.ReuseIfModelsEqualStrategy
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof DetachableContactModel) {
+			DetachableContactModel other = (DetachableContactModel) obj;
+			return other.id == this.id;
+		}
+		return false;
+	}
+
+	/**
+	 * @see wicket.model.AbstractDetachableModel#getNestedModel()
+	 */
+	@Override
+	public IModel getNestedModel() {
+		return null;
+	}
+
+	/**
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return new Long(id).hashCode();
+	}
+
+	protected ContactsDatabase getContactsDB() {
+		return DatabaseLocator.getDatabase();
+	}
+
+	@Override
+	protected void onAttach() {
+		if (contact == null) {
+			contact = getContactsDB().get(id);
+		}
+	}
+
+	@Override
+	protected void onDetach() {
+		contact = null;
+	}
+
+	@Override
+	protected Object onGetObject(Component component) {
+		return contact;
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/FormInputModel.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/FormInputModel.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/FormInputModel.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/FormInputModel.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,380 @@
+/*
+ * $Id: FormInputModel.java 4776 2006-03-05 17:10:05 -0800 (Sun, 05 Mar 2006)
+ * joco01 $ $Revision: 5394 $ $Date: 2006-03-05 17:10:05 -0800 (Sun, 05 Mar
+ * 2006) $
+ * 
+ * ==============================================================================
+ * Licensed 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 wicket.threadtest.apps.app1;
+
+import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Simple model object for FormInput example. Has a number of simple properties
+ * that can be retrieved and set.
+ */
+public final class FormInputModel implements Serializable {
+	/**
+	 * Represents a line of text. Hack to get around the fact that strings are
+	 * immutable.
+	 */
+	public final class Line implements Serializable {
+		private String text;
+
+		/**
+		 * Construct.
+		 * 
+		 * @param text
+		 */
+		public Line(String text) {
+			this.text = text;
+		}
+
+		/**
+		 * Gets text.
+		 * 
+		 * @return text
+		 */
+		public String getText() {
+			return text;
+		}
+
+		/**
+		 * Sets text.
+		 * 
+		 * @param text
+		 *            text
+		 */
+		public void setText(String text) {
+			this.text = text;
+		}
+
+		/**
+		 * @see java.lang.Object#toString()
+		 */
+		public String toString() {
+			return text;
+		}
+	}
+
+	private Boolean booleanProperty;
+
+	private Date dateProperty = new Date();
+
+	private Double doubleProperty = new Double(20.5);
+
+	private Integer integerInRangeProperty = new Integer(50);
+
+	private Integer integerProperty = new Integer(100);
+
+	private List<Line> lines = new ArrayList<Line>();
+
+	private String numberRadioChoice = (String) Home.NUMBERS.get(0);
+
+	private List numbersCheckGroup = new ArrayList();
+
+	private String numbersGroup;
+
+	/** US phone number with mask '(###) ###-####'. */
+	private UsPhoneNumber phoneNumberUS = new UsPhoneNumber("(123) 456-1234");
+
+	private Set siteSelection = new HashSet();
+
+	private String stringProperty = "test";
+
+	private URL urlProperty;
+
+	/**
+	 * Construct.
+	 */
+	public FormInputModel() {
+		try {
+			urlProperty = new URL("http://wicket.sourceforge.net");
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+		}
+		lines.add(new Line("line one"));
+		lines.add(new Line("line two"));
+		lines.add(new Line("line three"));
+	}
+
+	/**
+	 * Gets the booleanProperty.
+	 * 
+	 * @return booleanProperty
+	 */
+	public Boolean getBooleanProperty() {
+		return booleanProperty;
+	}
+
+	/**
+	 * Gets dateProperty.
+	 * 
+	 * @return dateProperty
+	 */
+	public Date getDateProperty() {
+		return dateProperty;
+	}
+
+	/**
+	 * Gets doubleProperty.
+	 * 
+	 * @return doubleProperty
+	 */
+	public Double getDoubleProperty() {
+		return doubleProperty;
+	}
+
+	/**
+	 * Gets integerInRangeProperty.
+	 * 
+	 * @return integerInRangeProperty
+	 */
+	public Integer getIntegerInRangeProperty() {
+		return integerInRangeProperty;
+	}
+
+	/**
+	 * Gets integerProperty.
+	 * 
+	 * @return integerProperty
+	 */
+	public Integer getIntegerProperty() {
+		return integerProperty;
+	}
+
+	/**
+	 * Gets lines.
+	 * 
+	 * @return lines
+	 */
+	public List<Line> getLines() {
+		return lines;
+	}
+
+	/**
+	 * Gets the favoriteColor.
+	 * 
+	 * @return favoriteColor
+	 */
+	public String getNumberRadioChoice() {
+		return numberRadioChoice;
+	}
+
+	/**
+	 * @return the numbers list
+	 */
+	public List getNumbersCheckGroup() {
+		return numbersCheckGroup;
+	}
+
+	/**
+	 * @return the group number
+	 */
+	public String getNumbersGroup() {
+		return this.numbersGroup;
+	}
+
+	/**
+	 * @return the phoneNumberUS
+	 */
+	public UsPhoneNumber getPhoneNumberUS() {
+		return phoneNumberUS;
+	}
+
+	/**
+	 * Gets the selectedSites.
+	 * 
+	 * @return selectedSites
+	 */
+	public Set getSiteSelection() {
+		return siteSelection;
+	}
+
+	/**
+	 * Gets stringProperty.
+	 * 
+	 * @return stringProperty
+	 */
+	public String getStringProperty() {
+		return stringProperty;
+	}
+
+	/**
+	 * Gets the urlProperty.
+	 * 
+	 * @return urlProperty
+	 */
+	public URL getUrlProperty() {
+		return urlProperty;
+	}
+
+	/**
+	 * Sets the booleanProperty.
+	 * 
+	 * @param booleanProperty
+	 *            booleanProperty
+	 */
+	public void setBooleanProperty(Boolean booleanProperty) {
+		this.booleanProperty = booleanProperty;
+	}
+
+	/**
+	 * Sets dateProperty.
+	 * 
+	 * @param dateProperty
+	 *            dateProperty
+	 */
+	public void setDateProperty(Date dateProperty) {
+		this.dateProperty = dateProperty;
+	}
+
+	/**
+	 * Sets doubleProperty.
+	 * 
+	 * @param doubleProperty
+	 *            doubleProperty
+	 */
+	public void setDoubleProperty(Double doubleProperty) {
+		this.doubleProperty = doubleProperty;
+	}
+
+	/**
+	 * Sets integerInRangeProperty.
+	 * 
+	 * @param integerInRangeProperty
+	 *            integerInRangeProperty
+	 */
+	public void setIntegerInRangeProperty(Integer integerInRangeProperty) {
+		this.integerInRangeProperty = integerInRangeProperty;
+	}
+
+	/**
+	 * Sets integerProperty.
+	 * 
+	 * @param integerProperty
+	 *            integerProperty
+	 */
+	public void setIntegerProperty(Integer integerProperty) {
+		this.integerProperty = integerProperty;
+	}
+
+	/**
+	 * Sets lines.
+	 * 
+	 * @param lines
+	 *            lines
+	 */
+	public void setLines(List<Line> lines) {
+		this.lines = lines;
+	}
+
+	/**
+	 * Sets the favoriteColor.
+	 * 
+	 * @param favoriteColor
+	 *            favoriteColor
+	 */
+	public void setNumberRadioChoice(String favoriteColor) {
+		this.numberRadioChoice = favoriteColor;
+	}
+
+	/**
+	 * Sets the number.
+	 * 
+	 * @param group
+	 *            number
+	 */
+	public void setNumbersGroup(String group) {
+		this.numbersGroup = group;
+	}
+
+	/**
+	 * @param phoneNumberUS
+	 *            the phoneNumberUS to set
+	 */
+	public void setPhoneNumberUS(UsPhoneNumber phoneNumberUS) {
+		this.phoneNumberUS = phoneNumberUS;
+	}
+
+	/**
+	 * Sets the selectedSites.
+	 * 
+	 * @param selectedSites
+	 *            selectedSites
+	 */
+	public void setSiteSelection(Set selectedSites) {
+		this.siteSelection = selectedSites;
+	}
+
+	/**
+	 * Sets stringProperty.
+	 * 
+	 * @param stringProperty
+	 *            stringProperty
+	 */
+	public void setStringProperty(String stringProperty) {
+		this.stringProperty = stringProperty;
+	}
+
+	/**
+	 * Sets the urlProperty.
+	 * 
+	 * @param urlProperty
+	 *            urlProperty
+	 */
+	public void setUrlProperty(URL urlProperty) {
+		this.urlProperty = urlProperty;
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		StringBuffer b = new StringBuffer();
+		b.append("[TestInputObject stringProperty = '").append(stringProperty).append("', integerProperty = ").append(
+				integerProperty).append(", doubleProperty = ").append(doubleProperty).append(", dateProperty = ")
+				.append(dateProperty).append(", booleanProperty = ").append(booleanProperty).append(
+						", integerInRangeProperty = ").append(integerInRangeProperty).append(", urlProperty = ")
+				.append(urlProperty).append(", phoneNumberUS = ").append(phoneNumberUS)
+				.append(", numberRadioChoice = ").append(numberRadioChoice).append(", numbersCheckgroup ").append(
+						numbersCheckGroup).append(", numberRadioGroup= ").append(numbersGroup);
+		b.append(", selected sites {");
+		for (Iterator i = siteSelection.iterator(); i.hasNext();) {
+			b.append(i.next());
+			if (i.hasNext()) {
+				b.append(",");
+			}
+		}
+		b.append("]");
+		b.append(", lines [");
+		for (Iterator i = lines.iterator(); i.hasNext();) {
+			b.append(i.next());
+			if (i.hasNext()) {
+				b.append(", ");
+			}
+		}
+		b.append("]");
+		b.append("]");
+		return b.toString();
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home$ActionPanel.html
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home%24ActionPanel.html?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home$ActionPanel.html (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home$ActionPanel.html Tue Oct 10 16:16:10 2006
@@ -0,0 +1,3 @@
+<wicket:panel>
+<a href="#" wicket:id="select">select</a>
+</wicket:panel>
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.html
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.html?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.html (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.html Tue Oct 10 16:16:10 2006
@@ -0,0 +1,88 @@
+<html>
+<body>
+<a href="#" wicket:id="link">go</a>
+<span style="display: block; border: 1px solid black;"> Selected
+Contact: <span wicket:id="selectedLabel">[selected contact]</span> </span>
+<br />
+<table cellspacing="0" class="dataview">
+  <tr>
+    <th>Actions</th>
+    <th>ID</th>
+    <th>First Name</th>
+    <th>Last Name</th>
+    <th>Home Phone</th>
+    <th>Cell Phone</th>
+  </tr>
+  <tr wicket:id="simple">
+    <td><span wicket:id="actions">[actions]</span></td>
+    <td><span wicket:id="contactid">[contactid]</span></td>
+    <td><span wicket:id="firstname">[firstname]</span></td>
+    <td><span wicket:id="lastname">[lastname]</span></td>
+    <td><span wicket:id="homephone">[homephone]</span></td>
+    <td><span wicket:id="cellphone">[cellphone]</span></td>
+  </tr>
+</table>
+<form wicket:id="inputForm" id="inputForm">
+<div>Use locale: <select wicket:id="localeSelect" />
+  <!--  option>locale1</option>
+      <option>locale2</option>
+    </select -->
+  <a href="#" wicket:id="defaultLocaleLink">[default]</a></div>
+<p>
+<fieldset><legend>Input Form</legend>
+<table id="inputFormTable">
+  <tr>
+    <td valign="top"><label for="stringProperty">String</label> <input
+      wicket:id="stringProperty" id="stringProperty" type="text"
+      size="40" /> <label for="integerProperty">Integer</label> <input
+      wicket:id="integerProperty" id="integerProperty" type="text"
+      size="40" /> <label for="doubleProperty">Double</label> <input
+      wicket:id="doubleProperty" id="doubleProperty" type="text"
+      size="40" /> <label wicket:id="dateLabel" for="dateProperty">Date</label>
+    <input wicket:id="dateProperty" id="dateProperty" type="text"
+      size="40" /> <span wicket:id="datePicker"></span> <label>Listview
+    in a Form</label>
+    <ul>
+      <li wicket:id="lines"><input type="text" wicket:id="lineEdit" />
+      </li>
+    </ul>
+    <label for="booleanProperty">Boolean</label> <input
+      wicket:id="booleanProperty" id="booleanProperty" type="checkbox" />
+    </td>
+    <td valign="top"><label for="integerInRangeProperty">Value
+    between 0 and 100</label> <input wicket:id="integerInRangeProperty"
+      id="integerInRangeProperty" type="text" size="40" /> <label
+      for="urlProperty">URL (has to be a valid url)</label> <input
+      wicket:id="urlProperty" id="urlProperty" type="text" size="40" />
+    <label for="phoneNumberUS">US phone number (mask: '(###)
+    ###-####')</label> <input wicket:id="phoneNumberUS" id="phoneNumberUS"
+      type="text" size="40" /> <label for="numberRadioChoice">select
+    a number (RadioChoice)</label> <span valign="top"
+      wicket:id="numberRadioChoice" id="numberRadioChoice"> <input
+      type="radio">foo</input> <input type="radio">bar</input> </span> <span
+      wicket:id="numbersGroup"> <label>select a number
+    (RadioGroup)</label> <span wicket:id="numbers"> <input type="radio"
+      wicket:id="radio" /> <span wicket:id="number">[this is
+    where number will be]</span> </span> </span> <span wicket:id="numbersCheckGroup">
+    <label>select one or more numbers (CheckGroup)</label> <span
+      wicket:id="numbers"> <input type="checkbox"
+      wicket:id="check" /> <span wicket:id="number">[this is
+    where number will be]</span> </span> </span> <label for="siteSelection">your
+    favorite sites</label> <select wicket:id="siteSelection" id="siteSelection">
+      <option>foo</option>
+      <option>bar</option>
+    </select></td>
+  </tr>
+  <tr>
+    <td colspan="2"><input wicket:id="saveButton" type="image"
+      value="buttonFactory:save:Save" /> <a wicket:id="resetButtonLink"
+      src=""> <img wicket:id="resetButtonImage"
+      value="buttonFactory:reset:Reset" /> </a></td>
+  </tr>
+</table>
+</fieldset>
+</form>
+
+<div id="feedbackPanel"><span wicket:id="feedback" /></div>
+</body>
+</html>

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,325 @@
+/*
+ * $Id: HelloWorld.java 5394 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006)
+ * jdonnerstag $ $Revision: 5394 $ $Date: 2006-04-16 15:36:52 +0200 (Sun, 16 Apr
+ * 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import wicket.AttributeModifier;
+import wicket.Component;
+import wicket.Session;
+import wicket.extensions.markup.html.datepicker.DatePicker;
+import wicket.extensions.markup.html.repeater.data.DataView;
+import wicket.extensions.markup.html.repeater.refreshing.Item;
+import wicket.markup.html.WebMarkupContainer;
+import wicket.markup.html.WebPage;
+import wicket.markup.html.basic.Label;
+import wicket.markup.html.form.Check;
+import wicket.markup.html.form.CheckBox;
+import wicket.markup.html.form.CheckGroup;
+import wicket.markup.html.form.ChoiceRenderer;
+import wicket.markup.html.form.DropDownChoice;
+import wicket.markup.html.form.Form;
+import wicket.markup.html.form.ImageButton;
+import wicket.markup.html.form.ListMultipleChoice;
+import wicket.markup.html.form.Radio;
+import wicket.markup.html.form.RadioChoice;
+import wicket.markup.html.form.RadioGroup;
+import wicket.markup.html.form.TextField;
+import wicket.markup.html.form.validation.NumberValidator;
+import wicket.markup.html.image.Image;
+import wicket.markup.html.link.Link;
+import wicket.markup.html.list.ListItem;
+import wicket.markup.html.list.ListView;
+import wicket.markup.html.panel.FeedbackPanel;
+import wicket.markup.html.panel.Panel;
+import wicket.model.AbstractReadOnlyModel;
+import wicket.model.CompoundPropertyModel;
+import wicket.model.IModel;
+import wicket.model.Model;
+import wicket.model.PropertyModel;
+import wicket.protocol.http.WebRequest;
+import wicket.util.convert.ConversionException;
+import wicket.util.convert.IConverter;
+import wicket.util.convert.MaskConverter;
+import wicket.util.convert.SimpleConverterAdapter;
+
+public class Home extends WebPage {
+
+	private class ActionPanel extends Panel {
+		/**
+		 * @param id
+		 *            component id
+		 * @param model
+		 *            model for contact
+		 */
+		public ActionPanel(String id, IModel model) {
+			super(id, model);
+			add(new Link("select") {
+				public void onClick() {
+					Home.this.selected = (Contact) getParent().getModelObject();
+				}
+			});
+		}
+	}
+
+	/**
+	 * Form for collecting input.
+	 */
+	private class InputForm extends Form {
+		/**
+		 * Construct.
+		 * 
+		 * @param name
+		 *            Component name
+		 */
+		public InputForm(String name) {
+			super(name, new CompoundPropertyModel(new FormInputModel()));
+			add(new LocaleDropDownChoice("localeSelect"));
+			add(new Link("defaultLocaleLink") {
+				public void onClick() {
+					WebRequest request = (WebRequest) getRequest();
+					setLocale(request.getLocale());
+				}
+			});
+			TextField stringTextField = new TextField("stringProperty");
+			stringTextField.setLabel(new Model("String"));
+			add(stringTextField);
+			TextField integerTextField = new TextField("integerProperty", Integer.class);
+			add(integerTextField.add(NumberValidator.POSITIVE));
+			add(new TextField("doubleProperty", Double.class));
+			WebMarkupContainer dateLabel = new WebMarkupContainer("dateLabel");
+			add(dateLabel);
+			TextField datePropertyTextField = new TextField("dateProperty", Date.class);
+			add(datePropertyTextField);
+			add(new DatePicker("datePicker", dateLabel, datePropertyTextField));
+			add(new TextField("integerInRangeProperty", Integer.class).add(NumberValidator.range(0, 100)));
+			add(new CheckBox("booleanProperty"));
+			RadioChoice rc = new RadioChoice("numberRadioChoice", NUMBERS).setSuffix("");
+			rc.setLabel(new Model("number"));
+			add(rc);
+
+			RadioGroup group = new RadioGroup("numbersGroup");
+			add(group);
+			ListView persons = new ListView("numbers", NUMBERS) {
+				protected void populateItem(ListItem item) {
+					item.add(new Radio("radio", item.getModel()));
+					item.add(new Label("number", item.getModelObjectAsString()));
+				};
+			};
+			group.add(persons);
+
+			CheckGroup checks = new CheckGroup("numbersCheckGroup");
+			add(checks);
+			ListView checksList = new ListView("numbers", NUMBERS) {
+				protected void populateItem(ListItem item) {
+					item.add(new Check("check", item.getModel()));
+					item.add(new Label("number", item.getModelObjectAsString()));
+				};
+			};
+			checks.add(checksList);
+
+			add(new ListMultipleChoice("siteSelection", SITES));
+
+			add(new TextField("urlProperty", URL.class) {
+				public IConverter getConverter() {
+					return new SimpleConverterAdapter() {
+						public Object toObject(String value) {
+							try {
+								return new URL(value.toString());
+							} catch (MalformedURLException e) {
+								throw new ConversionException("'" + value + "' is not a valid URL");
+							}
+						}
+
+						public String toString(Object value) {
+							return value != null ? value.toString() : null;
+						}
+					};
+				}
+			});
+
+			add(new TextField("phoneNumberUS", UsPhoneNumber.class) {
+				public IConverter getConverter() {
+					return new MaskConverter("(###) ###-####", UsPhoneNumber.class);
+				}
+			});
+
+			add(new LinesListView("lines"));
+
+			add(new ImageButton("saveButton"));
+
+			add(new Link("resetButtonLink") {
+				public void onClick() {
+					InputForm.this.modelChanged();
+				}
+			}.add(new Image("resetButtonImage")));
+		}
+
+		/**
+		 * @see wicket.markup.html.form.Form#onSubmit()
+		 */
+		public void onSubmit() {
+			info("Saved model " + getModelObject());
+		}
+	}
+
+	/** list view to be nested in the form. */
+	private static final class LinesListView extends ListView {
+
+		/**
+		 * Construct.
+		 * 
+		 * @param id
+		 */
+		public LinesListView(String id) {
+			super(id);
+			setReuseItems(true);
+		}
+
+		protected void populateItem(ListItem item) {
+			item.add(new TextField("lineEdit", new PropertyModel(item.getModel(), "text")));
+		}
+	}
+
+	/**
+	 * Choice for a locale.
+	 */
+	private final class LocaleChoiceRenderer extends ChoiceRenderer {
+		/**
+		 * Constructor.
+		 */
+		public LocaleChoiceRenderer() {
+		}
+
+		/**
+		 * @see wicket.markup.html.form.IChoiceRenderer#getDisplayValue(Object)
+		 */
+		public Object getDisplayValue(Object object) {
+			Locale locale = (Locale) object;
+			String display = locale.getDisplayName(getLocale());
+			return display;
+		}
+	}
+
+	/**
+	 * Dropdown with Locales.
+	 */
+	private final class LocaleDropDownChoice extends DropDownChoice {
+		/**
+		 * Construct.
+		 * 
+		 * @param id
+		 *            component id
+		 */
+		public LocaleDropDownChoice(String id) {
+			super(id, LOCALES, new LocaleChoiceRenderer());
+			setModel(new PropertyModel(Home.this, "locale"));
+		}
+
+		/**
+		 * @see wicket.markup.html.form.DropDownChoice#onSelectionChanged(java.lang.Object)
+		 */
+		public void onSelectionChanged(Object newSelection) {
+		}
+
+		/**
+		 * @see wicket.markup.html.form.DropDownChoice#wantOnSelectionChangedNotifications()
+		 */
+		protected boolean wantOnSelectionChangedNotifications() {
+			return true;
+		}
+	}
+
+	/** available numbers for the radio selection. */
+	static final List NUMBERS = Arrays.asList(new String[] { "1", "2", "3" });
+
+	/** Relevant locales wrapped in a list. */
+	private static final List LOCALES = Arrays.asList(new Locale[] { Locale.ENGLISH, new Locale("nl"), Locale.GERMAN,
+			Locale.SIMPLIFIED_CHINESE, Locale.JAPANESE, new Locale("pt", "BR"), new Locale("fa", "IR"),
+			new Locale("da", "DK") });
+
+	/** available sites for the multiple select. */
+	private static final List SITES = Arrays.asList(new String[] { "The Server Side", "Java Lobby", "Java.Net" });
+
+	private Contact selected;
+
+	public Home() {
+
+		add(new Link("link") {
+
+			@Override
+			public void onClick() {
+				System.out.println("click received for session " + Session.get());
+			}
+		});
+
+		add(new Label("selectedLabel", new PropertyModel(this, "selectedContactLabel")));
+
+		add(new DataView("simple", new ContactDataProvider()) {
+			protected void populateItem(final Item item) {
+				Contact contact = (Contact) item.getModelObject();
+				item.add(new ActionPanel("actions", item.getModel()));
+				item.add(new Label("contactid", String.valueOf(contact.getId())));
+				item.add(new Label("firstname", contact.getFirstName()));
+				item.add(new Label("lastname", contact.getLastName()));
+				item.add(new Label("homephone", contact.getHomePhone()));
+				item.add(new Label("cellphone", contact.getCellPhone()));
+
+				item.add(new AttributeModifier("class", true, new AbstractReadOnlyModel() {
+					public Object getObject(Component component) {
+						return (item.getIndex() % 2 == 1) ? "even" : "odd";
+					}
+				}));
+			}
+		});
+
+		final FeedbackPanel feedback = new FeedbackPanel("feedback");
+		add(feedback);
+		add(new InputForm("inputForm"));
+	}
+
+	/**
+	 * @return string representation of selceted contact property
+	 */
+	public String getSelectedContactLabel() {
+		if (selected == null) {
+			return "No Contact Selected";
+		} else {
+			return selected.getFirstName() + " " + selected.getLastName();
+		}
+	}
+
+	/**
+	 * Sets locale for the user's session (getLocale() is inherited from
+	 * Component)
+	 * 
+	 * @param locale
+	 *            The new locale
+	 */
+	public void setLocale(Locale locale) {
+		if (locale != null) {
+			getSession().setLocale(locale);
+		}
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.properties
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.properties?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.properties (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/Home.properties Tue Oct 10 16:16:10 2006
@@ -0,0 +1,2 @@
+inputForm.urlProperty.TypeValidator='${input}' is not a valid URL
+inputForm.phoneNumberUS.TypeValidator='${input}' is not a valid US phone number

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/TestApp1.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/TestApp1.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/TestApp1.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/TestApp1.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,53 @@
+/*
+ * $Id: HelloWorldApplication.java 5394 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006) jdonnerstag $
+ * $Revision: 5394 $ $Date: 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app1;
+
+import wicket.Application;
+import wicket.markup.html.image.resource.DefaultButtonImageResource;
+import wicket.protocol.http.WebApplication;
+
+public class TestApp1 extends WebApplication {
+
+	public static TestApp1 get() {
+		return (TestApp1) Application.get();
+	}
+
+	private ContactsDatabase contactsDB = new ContactsDatabase(50);
+
+	public TestApp1() {
+	}
+
+	/**
+	 * Gets contactsDB.
+	 * 
+	 * @return contactsDB
+	 */
+	public ContactsDatabase getContactsDB() {
+		return contactsDB;
+	}
+
+	@Override
+	public Class getHomePage() {
+		return Home.class;
+	}
+
+	@Override
+	protected void init() {
+		getSharedResources().add("cancelButton", new DefaultButtonImageResource("Cancel"));
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/UsPhoneNumber.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/UsPhoneNumber.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/UsPhoneNumber.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app1/UsPhoneNumber.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,73 @@
+/*
+ * $Id: FormInputModel.java 4776 2006-03-05 17:10:05 -0800 (Sun, 05 Mar 2006)
+ * joco01 $ $Revision: 4776 $ $Date: 2006-03-05 17:10:05 -0800 (Sun, 05 Mar
+ * 2006) $
+ * 
+ * ==============================================================================
+ * Licensed 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 wicket.threadtest.apps.app1;
+
+import java.io.Serializable;
+
+/**
+ * Represents a US phone number. We use this instead of the direct string to
+ * trigger conversion to and from string. Conversion in general may be
+ * re-evaluated in Wicket 1.3, hopefully making this a hack from the past by
+ * then.
+ * 
+ * @author Eelco Hillenius
+ */
+public class UsPhoneNumber implements Serializable
+{
+	private String number;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param number
+	 */
+	public UsPhoneNumber(String number)
+	{
+		this.number = number;
+	}
+
+	/**
+	 * Gets text.
+	 * 
+	 * @return text
+	 */
+	public String getNumber()
+	{
+		return number;
+	}
+
+	/**
+	 * Sets text.
+	 * 
+	 * @param number
+	 *            text
+	 */
+	public void setNumber(String number)
+	{
+		this.number = number;
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString()
+	{
+		return number;
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Connection.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Connection.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Connection.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Connection.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.apps.app2;
+
+import wicket.Session;
+
+public class Connection {
+
+	private final String id;
+
+	public Connection(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		return ((Connection) obj).id.equals(id);
+	}
+
+	public String getData() {
+		return "data[Connection=" + id + ",Session=" + Session.get() + ",Thread=" + Thread.currentThread() + "]";
+	}
+
+	/**
+	 * Gets id.
+	 * 
+	 * @return id
+	 */
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return "Connection[" + id + "]";
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.html
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.html?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.html (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.html Tue Oct 10 16:16:10 2006
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <span wicket:id="label">[label]</span>
+</body>
+</html>

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Home.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,40 @@
+/*
+ * $Id: HelloWorld.java 5394 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006)
+ * jdonnerstag $ $Revision: 5394 $ $Date: 2006-04-16 15:36:52 +0200 (Sun, 16 Apr
+ * 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app2;
+
+import wicket.Component;
+import wicket.markup.html.WebPage;
+import wicket.markup.html.basic.Label;
+import wicket.model.AbstractReadOnlyModel;
+import wicket.model.IModel;
+
+public class Home extends WebPage {
+
+	public Home() {
+
+		IModel model = new AbstractReadOnlyModel() {
+
+			@Override
+			public Object getObject(Component component) {
+				return Pool.getConnection().getData();
+			}
+		};
+		add(new Label("label", model));
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Pool.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Pool.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Pool.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/Pool.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,86 @@
+package wicket.threadtest.apps.app2;
+
+import java.util.Stack;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Test pool.
+ * 
+ * @author eelcohillenius
+ */
+public class Pool {
+
+	private static Pool _instance = new Pool();
+
+	private static Log log = LogFactory.getLog(Pool.class);
+
+	public static Connection getConnection() {
+		return getInstance().doGetConnection();
+	}
+
+	public static Pool getInstance() {
+		return _instance;
+	}
+
+	public static void release() {
+		getInstance().doRelease();
+	}
+
+	private Connection[] allConnections;
+
+	private Stack<Connection> available = new Stack<Connection>();
+
+	private ThreadLocal<Connection> locks = new ThreadLocal<Connection>();
+
+	private int size = 3;
+
+	private Pool() {
+
+		allConnections = new Connection[size];
+		for (int i = 0; i < size; i++) {
+			Connection connection = new Connection(String.valueOf(i));
+			allConnections[i] = connection;
+			available.push(connection);
+		}
+	}
+
+	private synchronized Connection doGetConnection() {
+
+		Connection c = locks.get();
+
+		if (c != null) {
+			return c;
+
+		} else {
+
+			while (c == null) {
+
+				if (!available.isEmpty()) {
+					c = available.pop();
+					locks.set(c);
+					log.info("returning " + c + " for " + Thread.currentThread());
+				} else {
+					try {
+						log.info("enter wait for " + Thread.currentThread());
+						wait();
+					} catch (InterruptedException e) {
+						throw new RuntimeException(e);
+					}
+				}
+			}
+		}
+		return c;
+	}
+
+	private synchronized void doRelease() {
+		Connection c = locks.get();
+		if (c != null) {
+			available.push(c);
+			locks.remove();
+			log.info("releasing " + c + " for " + Thread.currentThread());
+			notifyAll();
+		}
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestApp2.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestApp2.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestApp2.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestApp2.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,42 @@
+/*
+ * $Id: HelloWorldApplication.java 5394 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006) jdonnerstag $
+ * $Revision: 5394 $ $Date: 2006-04-16 15:36:52 +0200 (Sun, 16 Apr 2006) $
+ * 
+ * ==================================================================== Licensed
+ * 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 wicket.threadtest.apps.app2;
+
+import wicket.Application;
+import wicket.markup.html.image.resource.DefaultButtonImageResource;
+import wicket.protocol.http.WebApplication;
+
+public class TestApp2 extends WebApplication {
+
+	public static TestApp2 get() {
+		return (TestApp2) Application.get();
+	}
+
+	public TestApp2() {
+	}
+
+	@Override
+	public Class getHomePage() {
+		return Home.class;
+	}
+
+	@Override
+	protected void init() {
+		getSharedResources().add("cancelButton", new DefaultButtonImageResource("Cancel"));
+	}
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestFilter.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestFilter.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestFilter.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/apps/app2/TestFilter.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,43 @@
+package wicket.threadtest.apps.app2;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class TestFilter implements Filter {
+
+	private static final Log log = LogFactory.getLog(TestFilter.class);
+
+	/**
+	 * @see javax.servlet.Filter#destroy()
+	 */
+	public void destroy() {
+	}
+
+	/**
+	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
+	 *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
+	 */
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+			ServletException {
+
+		chain.doFilter(request, response);
+
+		Pool.release();
+	}
+
+	/**
+	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+	 */
+	public void init(FilterConfig config) throws ServletException {
+	}
+
+}

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractCommand.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractCommand.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractCommand.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractCommand.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,51 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.tester;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public abstract class AbstractCommand implements Command {
+
+	private static final Log log = LogFactory.getLog(AbstractCommand.class);
+
+	/** number of executions of the urls. */
+	private final int iterations;
+
+	/** URLs to visit. */
+	private final List<String> urls;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param urls
+	 *            URLs to visit
+	 * @param iterations
+	 *            number of executions of the urls
+	 */
+	public AbstractCommand(List<String> urls, int iterations) {
+		this.urls = urls;
+		this.iterations = iterations;
+	}
+
+	/**
+	 * Gets iterations.
+	 * 
+	 * @return iterations
+	 */
+	public int getIterations() {
+		return iterations;
+	}
+
+	/**
+	 * Gets urls.
+	 * 
+	 * @return urls
+	 */
+	public List<String> getUrls() {
+		return urls;
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractGetCommand.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractGetCommand.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractGetCommand.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/AbstractGetCommand.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,56 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.tester;
+
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import wicket.util.string.Strings;
+
+public abstract class AbstractGetCommand extends AbstractCommand {
+
+	private static final Log log = LogFactory.getLog(AbstractGetCommand.class);
+
+	/**
+	 * Construct.
+	 * 
+	 * @param urls
+	 *            URLs to visit
+	 * @param iterations
+	 *            number of executions of the urls
+	 */
+	public AbstractGetCommand(List<String> urls, int iterations) {
+		super(urls, iterations);
+	}
+
+	/**
+	 * @see wicket.threadtest.tester.Command#execute(CommandRunner)
+	 */
+	public void execute(CommandRunner runner) throws Exception {
+
+		int iterations = getIterations();
+		for (int i = 0; i < iterations; i++) {
+			List<String> urls = getUrls();
+			for (String url : urls) {
+
+				String modUrl = Strings.replaceAll(url, "${iteration}", String.valueOf(i)).toString();
+				doGet(runner.getClient(), modUrl);
+			}
+		}
+	}
+
+	/**
+	 * Execute a GET request using the provided url.
+	 * 
+	 * @param url
+	 *            The url to GET
+	 * @param client
+	 *            the http client
+	 * @throws Exception
+	 */
+	protected abstract void doGet(HttpClient client, String url) throws Exception;
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Command.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Command.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Command.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Command.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,22 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.tester;
+
+/**
+ * Command interface.
+ * 
+ * @author eelcohillenius
+ */
+public interface Command {
+
+	/**
+	 * Execute one iteration.
+	 * 
+	 * @param runner
+	 *            command runner that executes this command
+	 * 
+	 * @throws Exception
+	 */
+	void execute(CommandRunner runner) throws Exception;
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/CommandRunner.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/CommandRunner.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/CommandRunner.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/CommandRunner.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,68 @@
+package wicket.threadtest.tester;
+
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Runs a command.
+ * 
+ * @author eelcohillenius
+ */
+public class CommandRunner implements Runnable {
+
+	public static interface CommandRunnerObserver {
+
+		void onDone(CommandRunner runner);
+
+		void onError(CommandRunner runner, Exception e);
+	}
+
+	private static final Log log = LogFactory.getLog(CommandRunner.class);
+
+	private HttpClient client;
+
+	private final List<Command> commands;
+
+	private final CommandRunnerObserver observer;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param commands
+	 * @param client
+	 */
+	public CommandRunner(List<Command> commands, HttpClient client, CommandRunnerObserver observer) {
+		this.commands = commands;
+		this.client = client;
+		this.observer = observer;
+	}
+
+	/**
+	 * Gets the HTTP client.
+	 * 
+	 * @return the HTTP client
+	 */
+	public HttpClient getClient() {
+		return this.client;
+	}
+
+	/**
+	 * @see java.lang.Runnable#run()
+	 */
+	public void run() {
+
+		for (Command command : commands) {
+			try {
+				command.execute(this);
+			} catch (Exception e) {
+				log.fatal("execution of command " + command + ", thread " + Thread.currentThread() + " failed", e);
+				observer.onError(this, e);
+				return;
+			}
+		}
+		observer.onDone(this);
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/SimpleGetCommand.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/SimpleGetCommand.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/SimpleGetCommand.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/SimpleGetCommand.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,85 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.tester;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class SimpleGetCommand extends AbstractGetCommand {
+
+	private static final Log log = LogFactory.getLog(SimpleGetCommand.class);
+
+	private boolean printResponse = false;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param urls
+	 *            URLs to visit
+	 * @param iterations
+	 *            number of executions of the urls
+	 */
+	public SimpleGetCommand(List<String> urls, int iterations) {
+		super(urls, iterations);
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param url
+	 *            URL to visit
+	 * @param iterations
+	 *            number of executions of the urls
+	 */
+	public SimpleGetCommand(String url, int iterations) {
+		super(Arrays.asList(new String[] { url }), iterations);
+	}
+
+	/**
+	 * Gets printResponse.
+	 * 
+	 * @return printResponse
+	 */
+	public boolean getPrintResponse() {
+		return printResponse;
+	}
+
+	/**
+	 * Sets printResponse.
+	 * 
+	 * @param printResponse
+	 *            printResponse
+	 */
+	public void setPrintResponse(boolean printResponse) {
+		this.printResponse = printResponse;
+	}
+
+	/**
+	 * @see wicket.threadtest.tester.AbstractGetCommand#doGet(org.apache.commons.httpclient.HttpClient,
+	 *      java.lang.String)
+	 */
+	@Override
+	protected void doGet(HttpClient client, String url) throws Exception {
+
+		GetMethod method = new GetMethod(url);
+		method.setFollowRedirects(true);
+		try {
+			int code = client.executeMethod(method);
+			if (code != 200) {
+				log.error("ERROR! code: " + code);
+				throw new Exception(new String(method.getResponseBody()));
+			}
+			if (getPrintResponse()) {
+				log.info("\n" + new String(method.getResponseBody()));
+			}
+		} finally {
+			method.releaseConnection();
+		}
+	}
+}
\ No newline at end of file

Added: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Tester.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Tester.java?view=auto&rev=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Tester.java (added)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/main/java/wicket/threadtest/tester/Tester.java Tue Oct 10 16:16:10 2006
@@ -0,0 +1,188 @@
+/*
+ * Copyright Teachscape
+ */
+package wicket.threadtest.tester;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.params.HttpClientParams;
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.webapp.WebAppContext;
+
+import wicket.threadtest.tester.CommandRunner.CommandRunnerObserver;
+
+/**
+ * @author eelcohillenius
+ */
+public final class Tester implements CommandRunnerObserver {
+
+	private static final Log log = LogFactory.getLog(Tester.class);
+
+	private static HttpClientParams params;
+
+	static {
+		params = new HttpClientParams();
+		params.setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true);
+	}
+
+	private int activeThreads = 0;
+
+	private final List<Command> commands;
+
+	private String host = "localhost";
+
+	/**
+	 * if true, each thread will represent a seperate session. If false, the
+	 * test behaves like one client issuing multiple concurrent requests.
+	 */
+	private final boolean multipleSessions;
+
+	private final int numberOfThreads;
+
+	private int port = 8090;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param command
+	 *            Command to execute
+	 * @param numberOfThreads
+	 *            Number of threads to run the commands. Each thread runs all
+	 *            commands
+	 * @param multipleSessions
+	 *            if true, each thread will represent a seperate session. If
+	 *            false, the test behaves like one client issuing multiple
+	 *            concurrent requests
+	 */
+	public Tester(Command command, int numberOfThreads, boolean multipleSessions) {
+		this(Arrays.asList(new Command[] { command }), numberOfThreads, multipleSessions);
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param commands
+	 *            Commands to execute
+	 * @param numberOfThreads
+	 *            Number of threads to run the commands. Each thread runs all
+	 *            commands
+	 * @param multipleSessions
+	 *            if true, each thread will represent a seperate session. If
+	 *            false, the test behaves like one client issuing multiple
+	 *            concurrent requests
+	 */
+	public Tester(List<Command> commands, int numberOfThreads, boolean multipleSessions) {
+		this.commands = commands;
+		this.numberOfThreads = numberOfThreads;
+		this.multipleSessions = multipleSessions;
+	}
+
+	/**
+	 * Gets host.
+	 * 
+	 * @return host
+	 */
+	public String getHost() {
+		return host;
+	}
+
+	/**
+	 * Gets port.
+	 * 
+	 * @return port
+	 */
+	public int getPort() {
+		return port;
+	}
+
+	public void onDone(CommandRunner runner) {
+		activeThreads--;
+	}
+
+	public void onError(CommandRunner runner, Exception e) {
+		activeThreads--;
+	}
+
+	/**
+	 * Runs the test.
+	 * 
+	 * @throws Exception
+	 */
+	public void run() throws Exception {
+
+		activeThreads = 0;
+		Server server = new Server(port);
+		WebAppContext ctx = new WebAppContext("./src/webapp", "/");
+		server.addHandler(ctx);
+		server.start();
+
+		HttpConnectionManagerParams connManagerParams = new HttpConnectionManagerParams();
+		connManagerParams.setDefaultMaxConnectionsPerHost(numberOfThreads * 2);
+		MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
+		manager.setParams(connManagerParams);
+
+		try {
+
+			ThreadGroup g = new ThreadGroup("runners");
+			Thread[] threads = new Thread[numberOfThreads];
+			HttpClient client = null;
+			for (int i = 0; i < numberOfThreads; i++) {
+
+				if (multipleSessions) {
+					client = new HttpClient(params, manager);
+					client.getHostConfiguration().setHost(host, port);
+				} else {
+					if (client == null) {
+						client = new HttpClient(params, manager);
+						client.getHostConfiguration().setHost(host, port);
+					}
+				}
+				threads[i] = new Thread(g, new CommandRunner(commands, client, this));
+			}
+
+			long start = System.currentTimeMillis();
+
+			for (int i = 0; i < numberOfThreads; i++) {
+				activeThreads++;
+				threads[i].start();
+			}
+
+			while (activeThreads > 0) {
+				Thread.yield();
+			}
+
+			long end = System.currentTimeMillis();
+			log.info("\n******** finished in " + (end - start) + " miliseconds\n");
+
+		} finally {
+			MultiThreadedHttpConnectionManager.shutdownAll();
+			server.stop();
+		}
+	}
+
+	/**
+	 * Sets host.
+	 * 
+	 * @param host
+	 *            host
+	 */
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	/**
+	 * Sets port.
+	 * 
+	 * @param port
+	 *            port
+	 */
+	public void setPort(int port) {
+		this.port = port;
+	}
+}

Modified: incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/webapp/WEB-INF/web.xml?view=diff&rev=462634&r1=462633&r2=462634
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/webapp/WEB-INF/web.xml (original)
+++ incubator/wicket/branches/wicket-1.x/wicket-threadtest/src/webapp/WEB-INF/web.xml Tue Oct 10 16:16:10 2006
@@ -22,6 +22,16 @@
 	  <param-name>configuration</param-name>
 	  <param-value>deployment</param-value>
 	</context-param>
+	
+    <filter>
+        <filter-name>app2filter</filter-name>
+        <filter-class>wicket.threadtest.apps.app2.TestFilter</filter-class>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>app2filter</filter-name>
+        <url-pattern>/app2/*</url-pattern>
+    </filter-mapping>
 
 	<servlet>
 		<servlet-name>TestApp1</servlet-name>