You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by kn...@apache.org on 2007/10/11 21:40:51 UTC

svn commit: r583930 - in /wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket: ComponentSourceEntry.java IComponentSource.java IComponentSourceProvider.java

Author: knopp
Date: Thu Oct 11 12:40:50 2007
New Revision: 583930

URL: http://svn.apache.org/viewvc?rev=583930&view=rev
Log:
WICKET-1060

Added:
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java   (with props)
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java   (with props)
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java   (with props)

Added: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java?rev=583930&view=auto
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java (added)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java Thu Oct 11 12:40:50 2007
@@ -0,0 +1,328 @@
+/*
+ * 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.io.Serializable;
+import java.util.Iterator;
+
+import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Represents a "dehydrated" component state keeping only the minimum information needed to
+ * reconstruct the component. That includes component id, {@link IComponentSource} and componentInfo
+ * string. The string contains generated <code>markupID</code>s and <code>markupIndex</code>es
+ * of the component and all it's children. Those are wicket internal variables and it's up to wicket
+ * (not {@link IComponentSource} implementation to reconstruct that transparently for the user.
+ * These information are encoded as one string to minimize object overhead.
+ */
+abstract class ComponentSourceEntry implements Serializable
+{
+	private static final long serialVersionUID = 1L;
+
+	final String id;
+	private final IComponentSource componentSource;
+	private final String componentInfo;
+
+	/**
+	 * Checks if the component ID or markup ID doesn't contain invalid characters. This might be a
+	 * little more strict that default wicket rules, but it is necessary for the componentInfo
+	 * string
+	 * 
+	 * @param name
+	 * @param id
+	 */
+	private final void checkId(String name, String id)
+	{
+		if (id.indexOf('(') != -1 || id.indexOf('(') != -1 || id.indexOf(' ') != -1 ||
+				id.indexOf(',') != -1)
+		{
+			throw new IllegalStateException(name + "'" + id +
+					"' is not valid, it may not contain any of the ' ', '(', ')', ',' characters");
+		}
+	}
+
+	/**
+	 * Appends component state to info string
+	 * 
+	 * @param buffer
+	 * @param component
+	 */
+	private final void appendComponent(AppendingStringBuffer buffer, Component component)
+	{
+		checkId("Component id", component.getId());
+		buffer.append(component.getId());
+		buffer.append(' ');
+		if (component.hasMarkupIdMetaData())
+		{
+
+			checkId("Component markup id", component.getMarkupId());
+			// if the markup id starts with component id, append only the difference prefixed by '*'
+			if (component.getMarkupId().startsWith(component.getId()))
+			{
+				buffer.append('*');
+				buffer.append(component.getMarkupId().substring(component.getId().length()));
+			}
+			else
+			{
+				buffer.append(component.getMarkupId());
+			}
+			buffer.append(' ');
+		}
+		buffer.append(component.markupIndex);
+
+		if (component instanceof MarkupContainer &&
+				((MarkupContainer)component).iterator().hasNext())
+		{
+			buffer.append('(');
+
+			Iterator i = ((MarkupContainer)component).iterator();
+			while (i.hasNext())
+			{
+				Component child = (Component)i.next();
+				appendComponent(buffer, child);
+				if (i.hasNext())
+				{
+					buffer.append(',');
+				}
+			}
+
+			buffer.append(')');
+		}
+	}
+
+	/**
+	 * Creates a ComponentSourceEntry instance
+	 * 
+	 * @param container
+	 * @param component
+	 * @param componentSource
+	 */
+	ComponentSourceEntry(MarkupContainer container, Component component,
+			IComponentSource componentSource)
+	{
+		id = component.getId();
+
+		this.componentSource = componentSource;
+		AppendingStringBuffer buffer = new AppendingStringBuffer();
+		appendComponent(buffer, component);
+		componentInfo = buffer.toString();
+
+		System.out.println("Info: " + componentInfo);
+	}
+
+	/**
+	 * The subclass of this method calls private method on {@link MarkupContainer}, so it needs to
+	 * be implemented by a markup container inner class
+	 * 
+	 * @param parent
+	 * @param index
+	 * @param child
+	 */
+	protected abstract void setChild(MarkupContainer parent, int index, Component child);
+
+	/**
+	 * Reconstructs the component
+	 * 
+	 * @param parent
+	 *            parent of the component
+	 * @param index
+	 *            position in parent's children
+	 * @return
+	 */
+	Component reconstruct(MarkupContainer parent, int index)
+	{
+		Component component = componentSource.restoreComponent(id);
+
+		if (parent != null)
+		{
+			component.setParent(parent);
+		}
+
+		component.beforeRender();
+
+		parseComponentInfo(parent, componentInfo, component);
+
+		return component;
+	};
+
+	/**
+	 * Returns the first part of string that belongs to a single component
+	 * 
+	 * @param string
+	 * @return
+	 */
+	private static String getComponentSubString(String string)
+	{
+		int len = string.length();
+
+		int i = string.indexOf(',');
+		if (i != -1 && i < len)
+		{
+			len = i;
+		}
+
+		i = string.indexOf(')');
+		if (i != -1 && i < len)
+		{
+			len = i;
+		}
+
+		i = string.substring(0, len).indexOf('(');
+		if (i != -1 && i < len)
+		{
+			len = i;
+		}
+
+		return string.substring(0, len);
+	}
+
+	/**
+	 * Parses the component info substring and applies it to component with id specified in string
+	 * that belongs to 'parent'. If the component is a MarkupContainer, returns the component
+	 * instance otherwise returns null
+	 * 
+	 * @param parent
+	 * @param info
+	 * @param component
+	 * @return
+	 */
+	private static MarkupContainer applyComponentInfo(MarkupContainer parent, String info,
+			Component component)
+	{
+		if (parent == null)
+		{
+			return null;
+		}
+
+		String parts[] = info.split(" ");
+
+		final String id = parts[0];
+		final String markupId;
+		final int markupIndex;
+
+		if (parts.length == 2)
+		{
+			markupId = null;
+			markupIndex = Integer.parseInt(parts[1]);
+		}
+		else if (parts.length == 3)
+		{
+			if (parts[1] != null && parts[1].startsWith("*"))
+			{
+				markupId = id + parts[1].substring(1);
+			}
+			else
+			{
+				markupId = parts[1];
+			}
+			markupIndex = Integer.parseInt(parts[2]);
+		}
+		else
+		{
+			throw new IllegalArgumentException("Malformed component info string '" + info + "'.");
+		}
+
+		if (component == null)
+		{
+			component = parent.get(id);
+		}
+
+		if (component == null)
+		{
+			logger
+					.warn("Couldn't find component with id '" + id +
+							"'. This means that the component was not properly reconstructed from ComponentSource.");
+		}
+		else
+		{
+			if (markupId != null)
+			{
+				component.setMarkupId(markupId);
+			}
+			component.markupIndex = markupIndex;
+		}
+		return component instanceof MarkupContainer ? (MarkupContainer)component : null;
+	}
+
+	/**
+	 * Parses the info string and applies the stored attributes (markupId and markupIndex) to the
+	 * components (recursively)
+	 * 
+	 * @param component
+	 *            The initial (root) reconstructed component. We need to specify this component
+	 *            explicitly, because the parent still contains ComponentSourceEntry (and not the
+	 *            component itself) during reconstruction
+	 * @param parent
+	 * @param info
+	 * @return
+	 */
+	private static int parseComponentInfo(MarkupContainer parent, String info, Component component)
+	{
+		// find the first part for the component
+		final String substring = getComponentSubString(info);
+
+		// if it is followed by '(' it means there are children
+		int len = substring.length();
+		boolean hasChildren = false;
+		if (len < info.length() && info.charAt(len) == '(')
+		{
+			hasChildren = true;
+			++len; // skip the '('
+		}
+
+		final MarkupContainer child = applyComponentInfo(parent, substring, component);
+
+		if (hasChildren)
+		{
+			int i = 0;
+			String children = info.substring(len); // part with children info
+
+
+			while (i < children.length())
+			{
+				if (children.charAt(i) == ',')
+				{
+					++i; // skip the ',' that can be left there from previous child
+				}
+
+				i += parseComponentInfo(child, children.substring(i), null);
+
+				// if the child is followed by a ')' it means there are no more children left
+				if (children.charAt(i) == ')')
+				{
+					++i;
+					break;
+				}
+			}
+
+			// advance by the length of component part and the length of children part
+			return len + i;
+		}
+		else
+		{
+			// advance by the length of component part
+			return len;
+		}
+	}
+
+	private static final Logger logger = LoggerFactory.getLogger(ComponentSourceEntry.class);
+
+
+}
\ No newline at end of file

Propchange: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ComponentSourceEntry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java?rev=583930&view=auto
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java (added)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java Thu Oct 11 12:40:50 2007
@@ -0,0 +1,43 @@
+/*
+ * 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.io.Serializable;
+
+/**
+ * Interface for objects that are capable of reconstructing a component. The component and it's
+ * children must be in the exact state as they were before "dehydrating".
+ * <p>
+ * This is useful for parts of page that are memory heavy but easy to reconstruct. Between requests
+ * only the {@link IComponentSource} instance is kept, rather then actual component. The component
+ * is then reconstructed on first access
+ * <p>
+ * This feature is experimental.
+ * 
+ * @author Matej Knopp
+ */
+public interface IComponentSource extends Serializable
+{
+	/**
+	 * This method must reconstruct the component as it was before "dehydrating" it. Also it's
+	 * children must be reconstructed
+	 * 
+	 * @param id
+	 * @return
+	 */
+	public Component restoreComponent(String id);
+}

Propchange: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java?rev=583930&view=auto
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java (added)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java Thu Oct 11 12:40:50 2007
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Components that implement this interface indicate that they are able to provide a
+ * {@link IComponentSource}, which represents object with minimal state that is able to reconstruct
+ * a component.
+ * <p>
+ * This feature is experimental.
+ * 
+ * @author Matej Knopp
+ */
+public interface IComponentSourceProvider
+{
+	/**
+	 * Returns an {@link IComponentSource} instance
+	 * 
+	 * @return
+	 */
+	public IComponentSource getComponentSource();
+}

Propchange: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/IComponentSourceProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain