| 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 (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; |
| } |
| } |