blob: 0c90da9c7520efa81b9db6c99412976972746164 [file] [log] [blame]
package org.eclipse.jst.jsf.facelet.core.internal.registry.taglib;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.jst.jsf.facelet.core.internal.FaceletCorePlugin;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.ComponentTagDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.ConverterTagDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.FaceletLibraryClassTagLib;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.FaceletTaglibDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.FaceletTaglibFactory;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.FaceletXMLDefnTaglib;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.HandlerTagDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.SourceTagDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.TagDefn;
import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.faceletTaglib_1_0.ValidatorTagDefn;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A Facelet tag library document parser (dtd 1.0).
*
* @author cbateman
*
*/
public class TagModelParser
{
private static final String FACELET_TAGLIB_DTD_PATH = "/dtd/facelet-taglib_1_0.dtd"; //$NON-NLS-1$
private static final String ELEMENT_NAME_VALIDATOR_ID = "validator-id"; //$NON-NLS-1$
private static final String ELEMENT_NAME_CONVERTER_ID = "converter-id"; //$NON-NLS-1$
private static final String ELEMENT_NAME_RENDERER_TYPE = "renderer-type"; //$NON-NLS-1$
private static final String ELEMENT_NAME_COMPONENT_TYPE = "component-type"; //$NON-NLS-1$
private static final String ELEMENT_NAME_VALIDATOR = "validator"; //$NON-NLS-1$
private static final String ELEMENT_NAME_CONVERTER = "converter"; //$NON-NLS-1$
private static final String ELEMENT_NAME_COMPONENT = "component"; //$NON-NLS-1$
private static final String ELEMENT_NAME_HANDLER_CLASS = "handler-class"; //$NON-NLS-1$
private static final String ELEMENT_NAME_SOURCE = "source"; //$NON-NLS-1$
private static final String ELEMENT_NAME_TAG_NAME = "tag-name"; //$NON-NLS-1$
private static final String ELEMENT_NAME_TAG = "tag"; //$NON-NLS-1$
private static final String ELEMENT_NAME_NAMESPACE = "namespace"; //$NON-NLS-1$
private static final String ELEMENT_NAME_LIBRARY_CLASS = "library-class"; //$NON-NLS-1$
private static final String ELEMENT_NAME_FACELET_TAGLIB = "facelet-taglib"; //$NON-NLS-1$
private static final String URI_FACELET_TAGLIB_1_0_DTD = "facelet-taglib_1_0.dtd"; //$NON-NLS-1$
private static final String PUBLIC_DTD_FACELET_TAGLIB_1_0_DTD = "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"; //$NON-NLS-1$
/**
* @param is
* @param dtdSourcePath
* @return the taglib definition or null
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public static FaceletTaglibDefn loadFromInputStream(final InputStream is, final String dtdSourcePath) throws IOException, ParserConfigurationException, SAXException
{
final byte[] buffer = getBufferForEntry(is);
final InputStream dtdSource = getDefaultDTDSource(dtdSourcePath != null ? dtdSourcePath : FACELET_TAGLIB_DTD_PATH);
final FaceletTaglibDefn taglib = loadFromBuffer(buffer, dtdSource);
return taglib;
}
/**
* @param buffer
* @param defaultDtdStream
* @return the tag library definition (loaded EMF model) for the buffer
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public static FaceletTaglibDefn loadFromBuffer(final byte[] buffer,
final InputStream defaultDtdStream) throws IOException,
ParserConfigurationException, SAXException
{
final InputSource inputSource = new InputSource(
new ByteArrayInputStream(buffer));
final Document doc = TagModelParser.getDefaultTaglibDocument(
inputSource, new InputSource(defaultDtdStream));
final FaceletTaglibDefn tagLib = TagModelParser.processDocument(doc);
return tagLib;
}
/**
* @param path
* @return the input stream for the default bundle Facelet dtd.
* @throws IOException
*/
protected static InputStream getDefaultDTDSource(final String path) throws IOException
{
final URL url = FaceletCorePlugin.getDefault().getBundle().getEntry(path);
if (url != null)
{
return url.openStream();
}
return null;
}
/**
* @param is must be open. Caller is responsible for closing.
* @return load the stream into a byte buffer.
*/
protected static byte[] getBufferForEntry(final InputStream is)
{
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
final byte[] buffer = new byte[2048];
int bytesRead = 0;
try
{
while (((bytesRead = is.read(buffer))) != -1)
{
stream.write(buffer, 0, bytesRead);
}
}
catch (final IOException e)
{
FaceletCorePlugin.log("Error loading buffer", e); //$NON-NLS-1$
return null;
}
return stream.toByteArray();
}
/**
* @param taglibFile
* @param defaultDTDSource
* @return the default taglib dom Document
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public static Document getDefaultTaglibDocument(
final InputSource taglibFile, final InputSource defaultDTDSource)
throws IOException, ParserConfigurationException, SAXException
{
final DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
final DocumentBuilder builder = factory.newDocumentBuilder();
final DefaultHandler handler = new DefaultHandler()
{
@Override
public InputSource resolveEntity(final String publicId,
final String systemId) throws IOException, SAXException
{
if (PUBLIC_DTD_FACELET_TAGLIB_1_0_DTD.equals(publicId)
|| (systemId != null && systemId
.endsWith(URI_FACELET_TAGLIB_1_0_DTD)))
{
return defaultDTDSource;
}
return super.resolveEntity(publicId, systemId);
}
};
builder.setEntityResolver(handler);
return builder.parse(taglibFile);
}
/**
* @param doc
* @return the facelet tag library or null
*/
public static FaceletTaglibDefn processDocument(final Document doc)
{
Node curNode = null;
for (int i = 0; i < doc.getChildNodes().getLength(); i++)
{
curNode = doc.getChildNodes().item(i);
if (curNode.getNodeType() == Node.ELEMENT_NODE
&& ELEMENT_NAME_FACELET_TAGLIB
.equals(curNode.getNodeName()))
{
break;
}
}
if (curNode == null)
{
throw new IllegalArgumentException(
"Couldn't find facelet-taglib node"); //$NON-NLS-1$
}
for (int i = 0; i < curNode.getChildNodes().getLength(); i++)
{
final Node node = curNode.getChildNodes().item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
if (node.getTextContent() != null && ELEMENT_NAME_LIBRARY_CLASS.equals(node.getNodeName()))
{
final FaceletLibraryClassTagLib faceletLibraryClassTagLib = FaceletTaglibFactory.eINSTANCE
.createFaceletLibraryClassTagLib();
faceletLibraryClassTagLib.setLibraryClass(node
.getTextContent().trim());
return faceletLibraryClassTagLib;
}
return processFaceletTaglibWithTags(curNode);
}
}
return null;
}
private static FaceletXMLDefnTaglib processFaceletTaglibWithTags(
final Node node)
{
String namespace = null;
final List<Node> tagNodes = new ArrayList<Node>();
for (int i = 0; i < node.getChildNodes().getLength(); i++)
{
final Node childNode = node.getChildNodes().item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE)
{
if (ELEMENT_NAME_NAMESPACE.equals(childNode.getNodeName()))
{
namespace = childNode.getTextContent();
}
else if (ELEMENT_NAME_TAG.equals(childNode.getNodeName()))
{
tagNodes.add(childNode);
}
}
}
if (namespace != null)
{
final FaceletXMLDefnTaglib xmlDefnTaglib = FaceletTaglibFactory.eINSTANCE
.createFaceletXMLDefnTaglib();
xmlDefnTaglib.setNamespace(namespace);
for (final Node tagNode : tagNodes)
{
final TagDefn tag = createTagFromNode(namespace, tagNode);
if (tag != null)
{
xmlDefnTaglib.getTags().add(tag);
}
}
return xmlDefnTaglib;
}
return null;
}
private static TagDefn createTagFromNode(final String namespace,
final Node tagNode)
{
final Map<String, Node> children = indexChildren(tagNode);
Node node = children.get(ELEMENT_NAME_TAG_NAME);
if (node != null)
{
final String name = safeGetTextContext(node);
if (name == null)
{
return null;
}
node = children.get(ELEMENT_NAME_HANDLER_CLASS);
if (node != null)
{
final HandlerTagDefn handlerTag = FaceletTaglibFactory.eINSTANCE
.createHandlerTagDefn();
handlerTag.setHandlerClass(safeGetTextContext(node));
handlerTag.setName(name);
return handlerTag;
}
node = children.get(ELEMENT_NAME_SOURCE);
if (node != null)
{
final SourceTagDefn sourceTag = FaceletTaglibFactory.eINSTANCE
.createSourceTagDefn();
sourceTag.setSource(safeGetTextContext(node));
sourceTag.setName(name);
return sourceTag;
}
node = children.get(ELEMENT_NAME_COMPONENT);
if (node != null)
{
return createTagWithComponentType(namespace, name, node);
}
node = children.get(ELEMENT_NAME_CONVERTER);
if (node != null)
{
return createTagWithConverter(namespace, name, node);
}
node = children.get(ELEMENT_NAME_VALIDATOR);
if (node != null)
{
return createValidatorTag(namespace, name, node);
}
}
return null;
}
private static ComponentTagDefn createTagWithComponentType(
final String uri, final String tagName, final Node paramNode)
{
final Map<String, Node> componentChildren = indexChildren(paramNode);
Node node = componentChildren.get(ELEMENT_NAME_COMPONENT_TYPE);
if (node != null)
{
final String componentType = safeGetTextContext(node);
String rendererType = null;
String handlerClass = null;
node = componentChildren.get(ELEMENT_NAME_RENDERER_TYPE);
if (node != null)
{
rendererType = safeGetTextContext(node);
}
node = componentChildren.get(ELEMENT_NAME_HANDLER_CLASS);
if (node != null)
{
handlerClass = safeGetTextContext(node);
}
final ComponentTagDefn componentTag = FaceletTaglibFactory.eINSTANCE
.createComponentTagDefn();
componentTag.setName(tagName);
componentTag.setComponentType(componentType);
componentTag.setHandlerClass(handlerClass);
componentTag.setRendererType(rendererType);
return componentTag;
}
return null;
}
private static ConverterTagDefn createTagWithConverter(final String uri,
final String tagName, final Node paramNode)
{
final Map<String, Node> converterChildren = indexChildren(paramNode);
Node node = converterChildren.get(ELEMENT_NAME_CONVERTER_ID);
if (node != null)
{
final String converterId = safeGetTextContext(node);
String handlerClass = null;
node = converterChildren.get(ELEMENT_NAME_HANDLER_CLASS);
if (node != null)
{
handlerClass = safeGetTextContext(node);
}
final ConverterTagDefn converterTag = FaceletTaglibFactory.eINSTANCE
.createConverterTagDefn();
converterTag.setName(tagName);
converterTag.setConverterId(converterId);
converterTag.setHandlerClass(handlerClass);
return converterTag;
}
return null;
}
private static ValidatorTagDefn createValidatorTag(final String uri,
final String tagName, final Node paramNode)
{
final Map<String, Node> converterChildren = indexChildren(paramNode);
Node node = converterChildren.get(ELEMENT_NAME_VALIDATOR_ID);
if (node != null)
{
final String validatorId = safeGetTextContext(node);
String handlerClass = null;
node = converterChildren.get(ELEMENT_NAME_HANDLER_CLASS);
if (node != null)
{
handlerClass = safeGetTextContext(node);
}
final ValidatorTagDefn validatorTag = FaceletTaglibFactory.eINSTANCE
.createValidatorTagDefn();
validatorTag.setName(tagName);
validatorTag.setHandlerClass(handlerClass);
validatorTag.setValidatorId(validatorId);
return validatorTag;
}
return null;
}
private static Map<String, Node> indexChildren(final Node node)
{
final Map<String, Node> children = new HashMap<String, Node>();
final NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++)
{
final Node childNode = nodeList.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE)
{
children.put(childNode.getNodeName(), childNode);
}
}
return children;
}
private static String safeGetTextContext(final Node node)
{
String textContent = node.getTextContent();
if (textContent == null)
{
return null;
}
textContent = textContent.trim();
if ("".equals(textContent)) //$NON-NLS-1$
{
return null;
}
return textContent;
}
}