org.apache.wicket.ComponentSourceEntry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.ops4j.pax.wicket.service Show documentation
Show all versions of org.ops4j.pax.wicket.service Show documentation
Pax Wicket Service is an OSGi extension of the Wicket framework, allowing for dynamic loading and
unloading of Wicket components and pageSources.
/*
* 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.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 markupID
s and markupIndex
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 IClusterable
{
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(' ');
Object markupId = component.getMarkupIdImpl();
if (markupId != null)
{
if (markupId instanceof String)
{
checkId("Component markup id", (String)markupId);
}
// if the markup id is an integer, prefixed it with '*'
if (markupId instanceof Integer)
{
buffer.append('*');
}
buffer.append(markupId);
buffer.append(' ');
}
buffer.append(component.markupIndex);
if (component instanceof MarkupContainer &&
((MarkupContainer)component).iterator().hasNext())
{
buffer.append('(');
Iterator extends Component> i = ((MarkupContainer)component).iterator();
while (i.hasNext())
{
Component child = 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 reconstructed component
*/
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 first part of string that belongs to a single component
*/
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 component
if it is a markup container, null otherwise
*/
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 Object 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 = Integer.valueOf(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.setMarkupIdImpl(markupId);
}
component.markupIndex = (short)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 length of component info
*/
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);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy