blob: 124c1ba1d3c54eba9b5b363481078fb689724645 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 Oracle Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Oracle Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.pagedesigner.dtmanager.converter.internal;
import java.net.URL;
import javax.servlet.jsp.el.ELException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jst.jsf.common.metadata.Trait;
import org.eclipse.jst.jsf.common.metadata.internal.IImageDescriptorProvider;
import org.eclipse.jst.jsf.common.metadata.internal.IMetaDataSourceModelProvider;
import org.eclipse.jst.jsf.common.metadata.internal.IResourceURLProvider;
import org.eclipse.jst.pagedesigner.PDPlugin;
import org.eclipse.jst.pagedesigner.converter.IConverterFactory;
import org.eclipse.jst.pagedesigner.converter.ITagConverter;
import org.eclipse.jst.pagedesigner.dtmanager.DTManager;
import org.eclipse.jst.pagedesigner.dtmanager.IDTInfo;
import org.eclipse.jst.pagedesigner.dtmanager.converter.ITagConverterDecorator;
import org.eclipse.jst.pagedesigner.dtmanager.dtinfo.ResolveAttributeValue;
import org.eclipse.jst.pagedesigner.dtmanager.dtinfo.TagDecorateInfo;
import org.eclipse.jst.pagedesigner.preview.PageExpressionContext;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* ITagConverterDecorator implementation for DTTagConverter.
*
* @author Ian Trimble - Oracle
*/
public class DTTagConverterDecorator implements ITagConverterDecorator
{
private static final String DECORATE_INFO_ID_DESIGN = "vpd-decorate-design"; //$NON-NLS-1$
private static final String DECORATE_INFO_ID_PREVIEW = "vpd-decorate-preview"; //$NON-NLS-1$
private static final String MD_PLUGIN_LOCATION = "$metadata-plugin-location$"; //$NON-NLS-1$
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jst.pagedesigner.dtmanager.converter.ITagConverterDecorator
* #decorate(org.eclipse.jst.pagedesigner.converter.ITagConverter)
*/
public void decorate(ITagConverter tagConverter)
{
if (!(tagConverter instanceof DTTagConverter))
{
throw new IllegalArgumentException(
"ITagConverter argument must be an instance of DTTagConverter"); //$NON-NLS-1$
}
DTTagConverter dtTagConverter = (DTTagConverter) tagConverter;
if (dtTagConverter.getMode() == IConverterFactory.MODE_DESIGNER)
{
decorateFromDTInfo(dtTagConverter, DECORATE_INFO_ID_DESIGN);
} else if (dtTagConverter.getMode() == IConverterFactory.MODE_PREVIEW)
{
decorateFromDTInfo(dtTagConverter, DECORATE_INFO_ID_PREVIEW);
}
if (tagConverter.getResultElement() == null
&& tagConverter.isVisualByHTML())
{
createUnknownTagRepresentation(dtTagConverter);
}
}
/**
* Performs decoration of the specified DTTagConverter instance from IDTInfo
* (metadata) for the specified (by ID) TagDecorateInfo.
*
* @param dtTagConverter
* DTTagConverter instance.
* @param tagDecorateInfoID
* ID of the TagDecorateInfo to be located in metadata.
*/
protected void decorateFromDTInfo(DTTagConverter dtTagConverter,
String tagDecorateInfoID)
{
Element srcElement = dtTagConverter.getHostElement();
DTManager dtManager = DTManager.getInstance();
IDTInfo dtInfo = dtManager.getDTInfo(srcElement);
if (dtInfo != null)
{
TagDecorateInfo tdInfo = dtInfo
.getTagDecorateInfo(tagDecorateInfoID);
if (tdInfo != null)
{
dtTagConverter.setMultiLevel(tdInfo.isMultiLevel());
dtTagConverter.setNeedBorderDecorator(tdInfo
.isNeedBorderDecorator());
dtTagConverter.setNeedTableDecorator(tdInfo
.isNeedTableDecorator());
if (tdInfo.isNonVisual())
{
setNonVisual(dtTagConverter, dtInfo, tdInfo
.getNonVisualImagePath());
}
if (tdInfo.isResolveChildText())
{
resolveChildText(dtTagConverter.getResultElement(), dtInfo);
}
if (tdInfo.isSetNonVisualChildElements())
{
setNonVisualChildElements(dtTagConverter, srcElement);
}
dtTagConverter.setWidget(tdInfo.isWidget());
dtTagConverter.setMinHeight(tdInfo.getMinHeight());
dtTagConverter.setMinWidth(tdInfo.getMinWidth());
ResolveAttributeValue resAttrValue = tdInfo
.getResolveAttributeValue();
if (resAttrValue != null)
{
String attributeName = resAttrValue.getAttributeName();
if (attributeName != null && attributeName.length() > 0)
{
resolveAttributeValue(dtTagConverter.getHostElement(),
dtTagConverter.getResultElement(),
attributeName, dtInfo, tagDecorateInfoID);
}
}
}
}
}
/**
* Creates a visual representation result Element for an unknown tag.
*
* @param dtTagConverter
* DTTagConverter instance.
*/
protected void createUnknownTagRepresentation(DTTagConverter dtTagConverter)
{
Element element = dtTagConverter.createElement("span"); //$NON-NLS-1$
element.setAttribute("style", "color:red;font-weight:bold;"); //$NON-NLS-1$ //$NON-NLS-2$
Text text = dtTagConverter
.createText("<" + dtTagConverter.getHostElement().getTagName() + "/>"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(text);
dtTagConverter.setResultElement(element);
dtTagConverter.setWidget(true);
}
/**
* Adds child Elements of the specified source Element to the specified
* DTTagConverter instance's collection of non-visual children.
*
* @param dtTagConverter
* DTTagConverter instance.
* @param srcElement
* Source Element for which child Elements are to be added.
*/
protected void setNonVisualChildElements(DTTagConverter dtTagConverter,
Element srcElement)
{
NodeList childNodes = srcElement.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++)
{
Node curNode = childNodes.item(i);
if (curNode.getNodeType() == Node.ELEMENT_NODE)
{
dtTagConverter.addNonVisualChildElement((Element) curNode);
}
}
}
/**
* Performs simple EL resolution for the child Text Node of the specified
* source Element instance.
*
* @param srcElement
* Source Element for which child Text Node EL resolution is to
* be performed.
* @param dtInfo
* IDTInfo instance.
*/
protected void resolveChildText(Element srcElement, IDTInfo dtInfo)
{
if (srcElement != null)
{
NodeList childNodes = srcElement.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++)
{
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.TEXT_NODE)
{
Text textNode = (Text) childNode;
String textNodeValue = textNode.getNodeValue();
try
{
String newTextNodeValue;
if (textNodeValue.contains(MD_PLUGIN_LOCATION))
{
newTextNodeValue = resolveMDPluginLocation(
textNodeValue, dtInfo);
} else
{
newTextNodeValue = (String) PageExpressionContext
.getCurrent().evaluateExpression(
textNodeValue, String.class, null);
}
if (newTextNodeValue != null
&& !textNodeValue.equals(newTextNodeValue))
{
textNode.setNodeValue(newTextNodeValue);
}
} catch (Exception ex)
{
// ignore - could not resolve, do not change existing
// value
}
}
}
}
}
/**
* Performs simple EL resolution for the value of the specified attribute of
* the specified Element.
*
* @param srcElement
*
* @param targetElement
* Source Element instance.
* @param attributeName
* Name of attribute for which the value should be resolved.
* @param dtInfo
* IDTInfo instance.
* @param tagDecorateInfoID
*/
protected void resolveAttributeValue(Element srcElement,
Element targetElement, String attributeName, IDTInfo dtInfo,
String tagDecorateInfoID)
{
if (targetElement != null)
{
String oldAttributeValue = null;
String targetAttributeName = attributeName;
// determine if attributeName is XPath and re-target as appropriate
if (attributeName.contains("/")) { //$NON-NLS-1$
int lastSlashPos = attributeName.lastIndexOf("/"); //$NON-NLS-1$
String xPathExpression = attributeName.substring(0,
lastSlashPos);
XPath xPath = XPathFactory.newInstance().newXPath();
try
{
Object resultObject = xPath.evaluate(xPathExpression,
targetElement, XPathConstants.NODE);
if (resultObject instanceof Element)
{
targetElement = (Element) resultObject;
targetAttributeName = attributeName
.substring(lastSlashPos + 1);
}
else if (resultObject instanceof Text)
{
Node parentNode = ((Text)resultObject).getParentNode();
if (parentNode instanceof Element)
{
parentNode.normalize();
targetAttributeName = IAttributeValueResolver.TEXT_NODE_KEY;
oldAttributeValue = ((Text)resultObject).getNodeValue();
}
}
}
catch (XPathExpressionException xee)
{
// could not evaluate - leave targetElement and
// targetAttributeName unchanged
}
}
if (!IAttributeValueResolver.TEXT_NODE_KEY.equals(targetAttributeName))
{
oldAttributeValue = targetElement.getAttribute(targetAttributeName);
}
if (oldAttributeValue != null && oldAttributeValue.length() > 0)
{
String newAttributeValue;
if (oldAttributeValue.contains(MD_PLUGIN_LOCATION))
{
newAttributeValue = resolveMDPluginLocation(
oldAttributeValue, dtInfo);
}
else
{
newAttributeValue = resolveAttributeValue(srcElement,
targetElement, targetAttributeName,
oldAttributeValue, tagDecorateInfoID);
}
if (newAttributeValue != null
&& !oldAttributeValue.equals(newAttributeValue))
{
if (IAttributeValueResolver.TEXT_NODE_KEY
.equals(targetAttributeName))
{
for (int i = targetElement.getChildNodes().getLength()-1; i >= 0; i--)
{
Node childNode = targetElement.getChildNodes().item(i);
if (childNode.getNodeType() == Node.TEXT_NODE)
{
targetElement.removeChild(childNode);
}
}
targetElement.appendChild(targetElement.getOwnerDocument().createTextNode(newAttributeValue));
}
else
{
targetElement.setAttribute(targetAttributeName,
newAttributeValue);
}
}
}
}
}
private String resolveAttributeValue(final Element originalElement,
final Element convertedElement,
final String convertedAttributeName, final String oldAttributeValue,
final String tagDecorateInfoID)
{
String newValue = null;
boolean valueResolved = false;
final String[] result = new String[1];
for (final IAttributeValueResolver resolver : AttributeValueResolverRegistryReader
.getInstance().getExtensions())
{
SafeRunner.run(new ISafeRunnable()
{
public void handleException(Throwable exception)
{
PDPlugin
.log(
"While resolving attribute in converter decorator", exception); //$NON-NLS-1$
}
public void run() throws Exception
{
if (resolver.canResolve(originalElement,
convertedElement, convertedAttributeName, oldAttributeValue))
{
result[0] = resolver.resolveAttribute(
originalElement, convertedElement,
convertedAttributeName, oldAttributeValue);
}
}
});
if (result[0] != null)
{
newValue = result[0];
valueResolved = true;
break;
}
}
if (!valueResolved &&
// maintain backward compatibility: only do this default
// behaviour for the preview
tagDecorateInfoID.equals(DECORATE_INFO_ID_PREVIEW))
{
// fall- through to default case.
try
{
PageExpressionContext current = PageExpressionContext.getCurrent();
if (current != null)
{
return (String) current
.evaluateExpression(oldAttributeValue, String.class,
null);
}
} catch (ELException e)
{
// ignore. we will just return null since couldn't resolve
}
}
return newValue;
}
/**
* Resolves any instance of MD_PLUGIN_LOCATION in input String.
*
* @param input
* Input String.
* @param dtInfo
* IDTInfo instance.
* @return Input String with any instance of MD_PLUGIN_LOCATION resolved.
*/
protected String resolveMDPluginLocation(String input, IDTInfo dtInfo)
{
String output = input;
if (input != null && input.contains(MD_PLUGIN_LOCATION))
{
int tokenStart = input.indexOf(MD_PLUGIN_LOCATION);
int tokenEnd = tokenStart + MD_PLUGIN_LOCATION.length();
String prefix = input.substring(0, tokenStart);
String suffix = input.substring(tokenEnd);
Trait trait = dtInfo.getTrait();
IMetaDataSourceModelProvider mdSourceModelProvider = trait
.getSourceModelProvider();
IResourceURLProvider resourceURLProvider = (IResourceURLProvider) mdSourceModelProvider
.getAdapter(IResourceURLProvider.class);
URL url = resourceURLProvider.getResourceURL("/META-INF/"); //$NON-NLS-1$
String resolvedToken = url.toExternalForm();
resolvedToken = resolvedToken.substring(0,
resolvedToken.length() - 10);
output = prefix + resolvedToken + suffix;
}
return output;
}
/**
* Sets DTTagConverter instance as non-visual as HTML and sets the
* ImageDescriptor instance that DTTagConverter will use to return an Image
* for rendering.
*
* @param dtTagConverter
* DTTagConverter instance.
* @param dtInfo
* IDTInfo instance.
* @param imagePath
* Image path, relative to declaring plug-in.
*/
protected void setNonVisual(DTTagConverter dtTagConverter, IDTInfo dtInfo,
String imagePath)
{
dtTagConverter.setVisualByHTML(false);
if (imagePath != null && imagePath.length() > 0)
{
Trait trait = dtInfo.getTrait();
IImageDescriptorProvider imgDescProvider = (IImageDescriptorProvider) trait
.getSourceModelProvider().getAdapter(
IImageDescriptorProvider.class);
if (imgDescProvider != null)
{
ImageDescriptor imageDescriptor = imgDescProvider
.getImageDescriptor(imagePath);
dtTagConverter.setVisualImageDescriptor(imageDescriptor);
}
}
}
}