blob: 392226158f02b7865f2bc22a5de575ad5c4e5922 [file] [log] [blame]
package org.eclipse.jst.jsf.designtime.internal.view;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jst.jsf.common.runtime.internal.model.ViewObject;
import org.eclipse.jst.jsf.common.runtime.internal.model.component.ComponentFactory;
import org.eclipse.jst.jsf.common.runtime.internal.model.component.ComponentInfo;
import org.eclipse.jst.jsf.common.runtime.internal.model.decorator.ConverterDecorator;
import org.eclipse.jst.jsf.common.runtime.internal.model.decorator.Decorator;
import org.eclipse.jst.jsf.common.runtime.internal.model.decorator.ValidatorDecorator;
import org.eclipse.jst.jsf.designtime.context.DTFacesContext;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* A component tree construction strategy based on XML view definition
*
* @author cbateman
*
*/
public class XMLComponentTreeConstructionStrategy extends
ComponentTreeConstructionStrategy<Node, IDocument>
{
private final XMLViewDefnAdapter _adapter;
private final XMLViewObjectConstructionStrategy _objectConstructionStrategy;
/**
* @param adapter
* @param project
*/
public XMLComponentTreeConstructionStrategy(
final XMLViewDefnAdapter adapter, final IProject project)
{
_adapter = adapter;
_objectConstructionStrategy =
new XMLViewObjectConstructionStrategy(adapter,
new ComponentConstructionData(0, null, project));
}
@Override
public ComponentInfo createComponentTree(final DTFacesContext context,
final DTUIViewRoot viewRoot)
{
final IDocument container =
_adapter.getContainer(context, viewRoot.getViewId());
final List<Node> roots = _adapter.getViewDefnRoots(container);
if (roots.size() > 0)
{
_objectConstructionStrategy.getConstructionData().setIdCounter(0);
// can only handle a single root for XML; should be the DOM root
return buildComponentTree(roots.get(0), viewRoot, container);
}
return viewRoot;
}
private ComponentInfo buildComponentTree(final Node root,
final DTUIViewRoot viewRoot, final IDocument document)
{
final ComponentInfo dummyRoot =
ComponentFactory.createComponentInfo(null, null, null, true);
// populate the dummy root
recurseDOMModel(root, dummyRoot, document);
// try to extract the view defined root from the dummyRoot and update
// 'root' with its children.
populateViewRoot(viewRoot, dummyRoot.getChildren());
return viewRoot;
}
/**
* Tries to find the view defined view root in children and use it populate
* viewRoot. Children may sub-class to a different algorithm or, in some cases
* create an implicit (i.e. Facelets does this) view root if one is not
* explicitly created by the view definition.
*
* Regardless of the strategy, the following post-conditions must be true
*
* To the extend that children represent the top-level objects in the view
* under the presumed root, viewRoot must be populated with them either directly
* if the creation of a view root is implicit (i.e. Facelets) or through a
* valid view root declaration found in the view definition (i.e. f:view in JSP)
* found the children list.
*
* The default behaviour assumes the JSP case.
*
* TODO: add validation cases for missing view roots in JSP.
*
* @param viewRoot
* @param children
*/
protected void populateViewRoot(final DTUIViewRoot viewRoot, final List children)
{
ComponentInfo foundRoot = null;
// TODO: additional cases:
// 1) Valid case: view is a fragment and has one or more non-view root
// children
// 2) Invalid case: not a fragment and has no view root
// 3) Invalid case: any definition and has more than one view root
// 4) Invalid case: any definition and has component siblings to the
// view root
FIND_VIEWROOT: for (final Iterator it =
children.iterator(); it.hasNext();)
{
final ComponentInfo topLevelChild = (ComponentInfo) it.next();
if ("javax.faces.ViewRoot".equals(topLevelChild
.getComponentTypeInfo().getComponentType()))
{
foundRoot = topLevelChild;
break FIND_VIEWROOT;
}
}
if (foundRoot != null)
{
for (final Iterator it = foundRoot.getChildren().iterator(); it
.hasNext();)
{
final ComponentInfo child = (ComponentInfo) it.next();
final String facetName = foundRoot.getFacetName(child);
// if not a facet, add as a normal child
if (facetName == null)
{
viewRoot.addChild(child);
}
// if it is a facet, add as a facet
else
{
viewRoot.addFacet(facetName, child);
}
}
}
}
private void recurseDOMModel(final Node node, final ComponentInfo parent,
final IDocument document)
{
ViewObject mappedObject = null;
_objectConstructionStrategy.getConstructionData().setParent(parent);
mappedObject =
_adapter.mapToViewObject(node, _objectConstructionStrategy,
document);
ComponentInfo newParent = parent;
if (mappedObject instanceof ComponentInfo)
{
parent.addChild((ComponentInfo) mappedObject);
newParent = (ComponentInfo) mappedObject;
}
else if (mappedObject instanceof ConverterDecorator)
{
// TODO: validate for parent is not a ValueHolder
parent.addDecorator((Decorator) mappedObject,
ComponentFactory.CONVERTER);
}
else if (mappedObject instanceof ValidatorDecorator)
{
// TODO: validate for parent is a not an EditableValueHolder
parent.addDecorator((Decorator) mappedObject,
ComponentFactory.VALIDATOR);
}
final NodeList children = node.getChildNodes();
final int numChildren = children.getLength();
for (int i = 0; i < numChildren; i++)
{
recurseDOMModel(children.item(i), newParent, document);
}
}
}