You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2014/05/19 17:38:46 UTC

git commit: WICKET-5577 Generation of wicket ids with prefix / suffix

Repository: wicket
Updated Branches:
  refs/heads/master 5a3fd0d2a -> ccff0802a


WICKET-5577 Generation of wicket ids with prefix / suffix


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

Branch: refs/heads/master
Commit: ccff0802a729bc10d84ed876ec08d408efc377af
Parents: 5a3fd0d
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Mon May 19 18:38:01 2014 +0300
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Mon May 19 18:38:37 2014 +0300

----------------------------------------------------------------------
 .../main/java/org/apache/wicket/Component.java  |  53 +---------
 .../java/org/apache/wicket/ComponentQueue2.java | 104 -------------------
 .../apache/wicket/DefaultMarkupIdGenerator.java |  80 ++++++++++++++
 .../org/apache/wicket/IMarkupIdGenerator.java   |  32 ++++++
 .../apache/wicket/settings/MarkupSettings.java  |  29 ++++++
 .../apache/wicket/MarkupIdGeneratorTest.java    |  73 +++++++++++++
 6 files changed, 216 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/Component.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java b/wicket-core/src/main/java/org/apache/wicket/Component.java
index 0e91438..eed90a7 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Component.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
@@ -1498,57 +1498,8 @@ public abstract class Component
 	 */
 	public String getMarkupId(boolean createIfDoesNotExist)
 	{
-		Object storedMarkupId = getMarkupIdImpl();
-		if (storedMarkupId instanceof String)
-		{
-			return (String)storedMarkupId;
-		}
-
-		if (storedMarkupId == null && createIfDoesNotExist == false)
-		{
-			return null;
-		}
-
-		int generatedMarkupId = storedMarkupId instanceof Integer ? (Integer)storedMarkupId
-			: getSession().nextSequenceValue();
-
-		if (generatedMarkupId == 0xAD)
-		{
-			// WICKET-4559 skip suffix 'ad' because some ad-blocking solutions may hide the
-// component
-			generatedMarkupId = getSession().nextSequenceValue();
-		}
-
-		if (storedMarkupId == null)
-		{
-			setMarkupIdImpl(generatedMarkupId);
-		}
-
-		String markupIdPrefix = "id";
-		if (getApplication().usesDevelopmentConfig())
-		{
-			// in non-deployment mode we make the markup id include component id
-			// so it is easier to debug
-			markupIdPrefix = getId();
-		}
-
-		String markupIdPostfix = Integer.toHexString(generatedMarkupId).toLowerCase();
-
-		String markupId = markupIdPrefix + markupIdPostfix;
-
-		// make sure id is compliant with w3c requirements (starts with a letter)
-		char c = markupId.charAt(0);
-		if (!Character.isLetter(c))
-		{
-			markupId = "id" + markupId;
-		}
-
-		// escape some noncompliant characters
-		markupId = Strings.replaceAll(markupId, "_", "__").toString();
-		markupId = markupId.replace('.', '_');
-		markupId = markupId.replace('-', '_');
-		markupId = markupId.replace(' ', '_');
-
+		IMarkupIdGenerator markupIdGenerator = getApplication().getMarkupSettings().getMarkupIdGenerator();
+		String markupId = markupIdGenerator.generateMarkupId(this);
 		return markupId;
 	}
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java b/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
deleted file mode 100644
index 2ce3e8f..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.wicket.util.lang.Args;
-
-/**
- * Manages the component queue.
- * 
- * @author igor
- * 
- * @deprecated uses too much memory compared to ComponentQueue
- */
-class ComponentQueue2
-{
-	private static final int INITIAL = 8;
-
-	private Map<String, Component> queue;
-	private int queueSize = 0;
-
-	void add(Component... components)
-	{
-		for (Component component : components)
-		{
-			add(component);
-		}
-	}
-
-	void add(Component component)
-	{
-		Args.notNull(component, "component");
-
-		if (queue == null)
-		{
-			queue = new HashMap<>(INITIAL, 1);
-		}
-
-		Component old = queue.put(component.getId(), component);
-		if (old != null)
-		{
-			throw new WicketRuntimeException("A component with id: " + component.getId()
-					+ " has already been queued");
-		}
-		queueSize++;
-	}
-
-	Component remove(String id)
-	{
-		if (queue != null)
-		{
-			Component removed = queue.remove(id);
-			if (removed != null)
-			{
-				queueSize--;
-				if (isEmpty())
-				{
-					queue = null;
-				}
-				return removed;
-			}
-		}
-		return null;
-	}
-
-	public boolean isEmpty()
-	{
-		return queueSize == 0;
-	}
-
-	public Component get(String id)
-	{
-		if (queue != null)
-		{
-			return queue.get(id);
-		}
-		return null;
-	}
-
-	@Override
-	public String toString()
-	{
-		return "ComponentQueue{" +
-				"queueSize=" + queueSize +
-				", queue=" + queue +
-				'}';
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java b/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
new file mode 100644
index 0000000..4f5d90f
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * An implementation of IMarkupIdGenerator that uses the Session to generate
+ * sequence numbers for the component markup ids.
+ * As a prefix for the generated markup id in development mode it uses the component id
+ * and in production mode the string <em>id</em>.
+ */
+public class DefaultMarkupIdGenerator implements IMarkupIdGenerator
+{
+	@Override
+	public String generateMarkupId(Component component)
+	{
+		Object storedMarkupId = component.getMarkupIdImpl();
+		if (storedMarkupId instanceof String)
+		{
+			return (String)storedMarkupId;
+		}
+
+		Session session = component.getSession();
+		int generatedMarkupId = storedMarkupId instanceof Integer ? (Integer)storedMarkupId
+				: session.nextSequenceValue();
+
+		if (generatedMarkupId == 0xAD)
+		{
+			// WICKET-4559 skip suffix 'ad' because some ad-blocking solutions may hide the component
+			generatedMarkupId = session.nextSequenceValue();
+		}
+
+		if (storedMarkupId == null)
+		{
+			component.setMarkupIdImpl(generatedMarkupId);
+		}
+
+		String markupIdPrefix = "id";
+		if (component.getApplication().usesDevelopmentConfig())
+		{
+			// in non-deployment mode we make the markup id include component id
+			// so it is easier to debug
+			markupIdPrefix = component.getId();
+		}
+
+		String markupIdPostfix = Integer.toHexString(generatedMarkupId).toLowerCase();
+
+		String markupId = markupIdPrefix + markupIdPostfix;
+
+		// make sure id is compliant with w3c requirements (starts with a letter)
+		char c = markupId.charAt(0);
+		if (!Character.isLetter(c))
+		{
+			markupId = "id" + markupId;
+		}
+
+		// escape some noncompliant characters
+		markupId = Strings.replaceAll(markupId, "_", "__").toString();
+		markupId = markupId.replace('.', '_');
+		markupId = markupId.replace('-', '_');
+		markupId = markupId.replace(' ', '_');
+
+		return markupId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
new file mode 100644
index 0000000..6bd2e30
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Generates markup ids for components
+ */
+public interface IMarkupIdGenerator
+{
+	/**
+	 * Generates markup id for the given component
+	 *
+	 * @param component
+	 *              The component for which to generate a markup id
+	 * @return The generated markup id
+	 */
+	String generateMarkupId(Component component);
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
index f615340..72869f0 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
@@ -16,6 +16,8 @@
  */
 package org.apache.wicket.settings;
 
+import org.apache.wicket.DefaultMarkupIdGenerator;
+import org.apache.wicket.IMarkupIdGenerator;
 import org.apache.wicket.markup.MarkupFactory;
 import org.apache.wicket.util.lang.Args;
 
@@ -64,6 +66,12 @@ public class MarkupSettings
 	private boolean stripWicketTags = false;
 
 	/**
+	 * Generates the markup ids for the components with
+	 * {@link org.apache.wicket.Component#setOutputMarkupId(boolean) #setOutputMarkupId(true)}
+	 */
+	private IMarkupIdGenerator markupIdGenerator = new DefaultMarkupIdGenerator();
+
+	/**
 	 * Construct
 	 */
 	public MarkupSettings()
@@ -244,4 +252,25 @@ public class MarkupSettings
 		throwExceptionOnMissingXmlDeclaration = throwException;
 		return this;
 	}
+
+	/**
+	 * @return The configured generator for component markup ids
+	 */
+	public IMarkupIdGenerator getMarkupIdGenerator()
+	{
+		return markupIdGenerator;
+	}
+
+	/**
+	 * Sets a new IMarkupIdGenerator
+	 *
+	 * @param markupIdGenerator
+	 *          The generator of markup ids for the components
+	 * @return {@code this} object for chaining
+	 */
+	public MarkupSettings setMarkupIdGenerator(IMarkupIdGenerator markupIdGenerator)
+	{
+		this.markupIdGenerator = Args.notNull(markupIdGenerator, "markupIdGenerator");
+		return this;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java b/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
new file mode 100644
index 0000000..859f620
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.wicket.markup.html.link.Link;
+import org.junit.Test;
+
+/**
+ * Tests for IMarkupIdGenerator
+ *
+ * @since 6.16.0
+ * @see <a href="https://issues.apache.org/jira/browse/WICKET-5577">Generation of wicket ids with prefix / suffix</a>
+ */
+public class MarkupIdGeneratorTest extends WicketTestCase
+{
+	@Test
+	public void defaultMarkupIdGenerator()
+	{
+		MockPageWithLink page = new MockPageWithLink();
+		Link link = new Link(MockPageWithLink.LINK_ID)
+		{
+			@Override
+			public void onClick()
+			{
+			}
+		};
+		link.setOutputMarkupId(true);
+		page.add(link);
+
+		assertEquals("link1", link.getMarkupId());
+	}
+
+	@Test
+	public void customMarkupIdGenerator()
+	{
+		final String customMarkupId = "custom";
+		IMarkupIdGenerator generator = new IMarkupIdGenerator()
+		{
+			@Override
+			public String generateMarkupId(Component component)
+			{
+				return customMarkupId;
+			}
+		};
+		tester.getApplication().getMarkupSettings().setMarkupIdGenerator(generator);
+		MockPageWithLink page = new MockPageWithLink();
+		Link link = new Link(MockPageWithLink.LINK_ID)
+		{
+			@Override
+			public void onClick()
+			{
+			}
+		};
+		link.setOutputMarkupId(true);
+		page.add(link);
+
+		assertEquals(customMarkupId, link.getMarkupId());
+	}
+}


Re: git commit: WICKET-5577 Generation of wicket ids with prefix / suffix

Posted by Martin Grigorov <mg...@apache.org>.
Accidentally with this commit I also removed ComponentQueue2 (it should
have been a separate commit).
This is the version of org.apache.wicket.ComponentQueue with the HashMap
impl. It proved to be slow and is not actually used.

Martin Grigorov
Wicket Training and Consulting


On Mon, May 19, 2014 at 6:38 PM, <mg...@apache.org> wrote:

> Repository: wicket
> Updated Branches:
>   refs/heads/master 5a3fd0d2a -> ccff0802a
>
>
> WICKET-5577 Generation of wicket ids with prefix / suffix
>
>
> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/ccff0802
> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/ccff0802
> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/ccff0802
>
> Branch: refs/heads/master
> Commit: ccff0802a729bc10d84ed876ec08d408efc377af
> Parents: 5a3fd0d
> Author: Martin Tzvetanov Grigorov <mg...@apache.org>
> Authored: Mon May 19 18:38:01 2014 +0300
> Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
> Committed: Mon May 19 18:38:37 2014 +0300
>
> ----------------------------------------------------------------------
>  .../main/java/org/apache/wicket/Component.java  |  53 +---------
>  .../java/org/apache/wicket/ComponentQueue2.java | 104 -------------------
>  .../apache/wicket/DefaultMarkupIdGenerator.java |  80 ++++++++++++++
>  .../org/apache/wicket/IMarkupIdGenerator.java   |  32 ++++++
>  .../apache/wicket/settings/MarkupSettings.java  |  29 ++++++
>  .../apache/wicket/MarkupIdGeneratorTest.java    |  73 +++++++++++++
>  6 files changed, 216 insertions(+), 155 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/Component.java
> ----------------------------------------------------------------------
> diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java
> b/wicket-core/src/main/java/org/apache/wicket/Component.java
> index 0e91438..eed90a7 100644
> --- a/wicket-core/src/main/java/org/apache/wicket/Component.java
> +++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
> @@ -1498,57 +1498,8 @@ public abstract class Component
>          */
>         public String getMarkupId(boolean createIfDoesNotExist)
>         {
> -               Object storedMarkupId = getMarkupIdImpl();
> -               if (storedMarkupId instanceof String)
> -               {
> -                       return (String)storedMarkupId;
> -               }
> -
> -               if (storedMarkupId == null && createIfDoesNotExist ==
> false)
> -               {
> -                       return null;
> -               }
> -
> -               int generatedMarkupId = storedMarkupId instanceof Integer
> ? (Integer)storedMarkupId
> -                       : getSession().nextSequenceValue();
> -
> -               if (generatedMarkupId == 0xAD)
> -               {
> -                       // WICKET-4559 skip suffix 'ad' because some
> ad-blocking solutions may hide the
> -// component
> -                       generatedMarkupId =
> getSession().nextSequenceValue();
> -               }
> -
> -               if (storedMarkupId == null)
> -               {
> -                       setMarkupIdImpl(generatedMarkupId);
> -               }
> -
> -               String markupIdPrefix = "id";
> -               if (getApplication().usesDevelopmentConfig())
> -               {
> -                       // in non-deployment mode we make the markup id
> include component id
> -                       // so it is easier to debug
> -                       markupIdPrefix = getId();
> -               }
> -
> -               String markupIdPostfix =
> Integer.toHexString(generatedMarkupId).toLowerCase();
> -
> -               String markupId = markupIdPrefix + markupIdPostfix;
> -
> -               // make sure id is compliant with w3c requirements (starts
> with a letter)
> -               char c = markupId.charAt(0);
> -               if (!Character.isLetter(c))
> -               {
> -                       markupId = "id" + markupId;
> -               }
> -
> -               // escape some noncompliant characters
> -               markupId = Strings.replaceAll(markupId, "_",
> "__").toString();
> -               markupId = markupId.replace('.', '_');
> -               markupId = markupId.replace('-', '_');
> -               markupId = markupId.replace(' ', '_');
> -
> +               IMarkupIdGenerator markupIdGenerator =
> getApplication().getMarkupSettings().getMarkupIdGenerator();
> +               String markupId = markupIdGenerator.generateMarkupId(this);
>                 return markupId;
>         }
>
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
> b/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
> deleted file mode 100644
> index 2ce3e8f..0000000
> --- a/wicket-core/src/main/java/org/apache/wicket/ComponentQueue2.java
> +++ /dev/null
> @@ -1,104 +0,0 @@
> -/*
> - * 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;
> -
> -import java.util.HashMap;
> -import java.util.Map;
> -
> -import org.apache.wicket.util.lang.Args;
> -
> -/**
> - * Manages the component queue.
> - *
> - * @author igor
> - *
> - * @deprecated uses too much memory compared to ComponentQueue
> - */
> -class ComponentQueue2
> -{
> -       private static final int INITIAL = 8;
> -
> -       private Map<String, Component> queue;
> -       private int queueSize = 0;
> -
> -       void add(Component... components)
> -       {
> -               for (Component component : components)
> -               {
> -                       add(component);
> -               }
> -       }
> -
> -       void add(Component component)
> -       {
> -               Args.notNull(component, "component");
> -
> -               if (queue == null)
> -               {
> -                       queue = new HashMap<>(INITIAL, 1);
> -               }
> -
> -               Component old = queue.put(component.getId(), component);
> -               if (old != null)
> -               {
> -                       throw new WicketRuntimeException("A component with
> id: " + component.getId()
> -                                       + " has already been queued");
> -               }
> -               queueSize++;
> -       }
> -
> -       Component remove(String id)
> -       {
> -               if (queue != null)
> -               {
> -                       Component removed = queue.remove(id);
> -                       if (removed != null)
> -                       {
> -                               queueSize--;
> -                               if (isEmpty())
> -                               {
> -                                       queue = null;
> -                               }
> -                               return removed;
> -                       }
> -               }
> -               return null;
> -       }
> -
> -       public boolean isEmpty()
> -       {
> -               return queueSize == 0;
> -       }
> -
> -       public Component get(String id)
> -       {
> -               if (queue != null)
> -               {
> -                       return queue.get(id);
> -               }
> -               return null;
> -       }
> -
> -       @Override
> -       public String toString()
> -       {
> -               return "ComponentQueue{" +
> -                               "queueSize=" + queueSize +
> -                               ", queue=" + queue +
> -                               '}';
> -       }
> -}
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
> b/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
> new file mode 100644
> index 0000000..4f5d90f
> --- /dev/null
> +++
> b/wicket-core/src/main/java/org/apache/wicket/DefaultMarkupIdGenerator.java
> @@ -0,0 +1,80 @@
> +/*
> + * 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;
> +
> +import org.apache.wicket.util.string.Strings;
> +
> +/**
> + * An implementation of IMarkupIdGenerator that uses the Session to
> generate
> + * sequence numbers for the component markup ids.
> + * As a prefix for the generated markup id in development mode it uses
> the component id
> + * and in production mode the string <em>id</em>.
> + */
> +public class DefaultMarkupIdGenerator implements IMarkupIdGenerator
> +{
> +       @Override
> +       public String generateMarkupId(Component component)
> +       {
> +               Object storedMarkupId = component.getMarkupIdImpl();
> +               if (storedMarkupId instanceof String)
> +               {
> +                       return (String)storedMarkupId;
> +               }
> +
> +               Session session = component.getSession();
> +               int generatedMarkupId = storedMarkupId instanceof Integer
> ? (Integer)storedMarkupId
> +                               : session.nextSequenceValue();
> +
> +               if (generatedMarkupId == 0xAD)
> +               {
> +                       // WICKET-4559 skip suffix 'ad' because some
> ad-blocking solutions may hide the component
> +                       generatedMarkupId = session.nextSequenceValue();
> +               }
> +
> +               if (storedMarkupId == null)
> +               {
> +                       component.setMarkupIdImpl(generatedMarkupId);
> +               }
> +
> +               String markupIdPrefix = "id";
> +               if (component.getApplication().usesDevelopmentConfig())
> +               {
> +                       // in non-deployment mode we make the markup id
> include component id
> +                       // so it is easier to debug
> +                       markupIdPrefix = component.getId();
> +               }
> +
> +               String markupIdPostfix =
> Integer.toHexString(generatedMarkupId).toLowerCase();
> +
> +               String markupId = markupIdPrefix + markupIdPostfix;
> +
> +               // make sure id is compliant with w3c requirements (starts
> with a letter)
> +               char c = markupId.charAt(0);
> +               if (!Character.isLetter(c))
> +               {
> +                       markupId = "id" + markupId;
> +               }
> +
> +               // escape some noncompliant characters
> +               markupId = Strings.replaceAll(markupId, "_",
> "__").toString();
> +               markupId = markupId.replace('.', '_');
> +               markupId = markupId.replace('-', '_');
> +               markupId = markupId.replace(' ', '_');
> +
> +               return markupId;
> +       }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
> b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
> new file mode 100644
> index 0000000..6bd2e30
> --- /dev/null
> +++ b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java
> @@ -0,0 +1,32 @@
> +/*
> + * 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;
> +
> +/**
> + * Generates markup ids for components
> + */
> +public interface IMarkupIdGenerator
> +{
> +       /**
> +        * Generates markup id for the given component
> +        *
> +        * @param component
> +        *              The component for which to generate a markup id
> +        * @return The generated markup id
> +        */
> +       String generateMarkupId(Component component);
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
> b/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
> index f615340..72869f0 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/settings/MarkupSettings.java
> @@ -16,6 +16,8 @@
>   */
>  package org.apache.wicket.settings;
>
> +import org.apache.wicket.DefaultMarkupIdGenerator;
> +import org.apache.wicket.IMarkupIdGenerator;
>  import org.apache.wicket.markup.MarkupFactory;
>  import org.apache.wicket.util.lang.Args;
>
> @@ -64,6 +66,12 @@ public class MarkupSettings
>         private boolean stripWicketTags = false;
>
>         /**
> +        * Generates the markup ids for the components with
> +        * {@link org.apache.wicket.Component#setOutputMarkupId(boolean)
> #setOutputMarkupId(true)}
> +        */
> +       private IMarkupIdGenerator markupIdGenerator = new
> DefaultMarkupIdGenerator();
> +
> +       /**
>          * Construct
>          */
>         public MarkupSettings()
> @@ -244,4 +252,25 @@ public class MarkupSettings
>                 throwExceptionOnMissingXmlDeclaration = throwException;
>                 return this;
>         }
> +
> +       /**
> +        * @return The configured generator for component markup ids
> +        */
> +       public IMarkupIdGenerator getMarkupIdGenerator()
> +       {
> +               return markupIdGenerator;
> +       }
> +
> +       /**
> +        * Sets a new IMarkupIdGenerator
> +        *
> +        * @param markupIdGenerator
> +        *          The generator of markup ids for the components
> +        * @return {@code this} object for chaining
> +        */
> +       public MarkupSettings setMarkupIdGenerator(IMarkupIdGenerator
> markupIdGenerator)
> +       {
> +               this.markupIdGenerator = Args.notNull(markupIdGenerator,
> "markupIdGenerator");
> +               return this;
> +       }
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/ccff0802/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
> b/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
> new file mode 100644
> index 0000000..859f620
> --- /dev/null
> +++
> b/wicket-core/src/test/java/org/apache/wicket/MarkupIdGeneratorTest.java
> @@ -0,0 +1,73 @@
> +/*
> + * 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;
> +
> +import org.apache.wicket.markup.html.link.Link;
> +import org.junit.Test;
> +
> +/**
> + * Tests for IMarkupIdGenerator
> + *
> + * @since 6.16.0
> + * @see <a href="https://issues.apache.org/jira/browse/WICKET-5577">Generation
> of wicket ids with prefix / suffix</a>
> + */
> +public class MarkupIdGeneratorTest extends WicketTestCase
> +{
> +       @Test
> +       public void defaultMarkupIdGenerator()
> +       {
> +               MockPageWithLink page = new MockPageWithLink();
> +               Link link = new Link(MockPageWithLink.LINK_ID)
> +               {
> +                       @Override
> +                       public void onClick()
> +                       {
> +                       }
> +               };
> +               link.setOutputMarkupId(true);
> +               page.add(link);
> +
> +               assertEquals("link1", link.getMarkupId());
> +       }
> +
> +       @Test
> +       public void customMarkupIdGenerator()
> +       {
> +               final String customMarkupId = "custom";
> +               IMarkupIdGenerator generator = new IMarkupIdGenerator()
> +               {
> +                       @Override
> +                       public String generateMarkupId(Component component)
> +                       {
> +                               return customMarkupId;
> +                       }
> +               };
> +
> tester.getApplication().getMarkupSettings().setMarkupIdGenerator(generator);
> +               MockPageWithLink page = new MockPageWithLink();
> +               Link link = new Link(MockPageWithLink.LINK_ID)
> +               {
> +                       @Override
> +                       public void onClick()
> +                       {
> +                       }
> +               };
> +               link.setOutputMarkupId(true);
> +               page.add(link);
> +
> +               assertEquals(customMarkupId, link.getMarkupId());
> +       }
> +}
>
>