All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jsftoolkit.gen.ConfigurationUpdater Maven / Gradle / Ivy

Go to download

The core classes for the JSF Toolkit Component Framework. Includes all framework base and utility classes as well as component kick-start/code-generation and registration tools. Also includes some classes for testing that are reused in other projects. They cannot be factored out into a separate project because they are referenced by the tests and they reference this code (circular dependence).

The newest version!
package com.jsftoolkit.gen;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathVariableResolver;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.jsftoolkit.gen.info.ComponentInfo;
import com.jsftoolkit.gen.info.PropertyInfo;
import com.jsftoolkit.utils.DeferedFileOutputStream;
import com.jsftoolkit.utils.Utils;

/**
 * This class updates configuration files as necessary to register a component.
 * 

* This class is safe for concurrent usage by multiple threads, however, as one * might expect, concurrent updates to the same configuration file will have an * undefined result. * * @author noah * */ public class ConfigurationUpdater { private DocumentBuilder documentBuilder; private XPathExpression firstComponent; /** * Holds variables for the XPath variable resolver. */ private ThreadLocal> vars = new ThreadLocal>() { @Override protected Map initialValue() { return new HashMap(); } }; private XPathExpression existingComponent; private XPathExpression existingRenderer; private XPathExpression firstRenderer; private XPathExpression renderKit; private XPathExpression existingTag; private XPathExpression componentElement; private XPathExpression existingTldTag; private XPathExpression attributeElement; protected static ConfigurationUpdater instance; protected ConfigurationUpdater() throws ParserConfigurationException, XPathExpressionException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); documentBuilder = factory.newDocumentBuilder(); documentBuilder.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // grrr, facelets... if ("-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" .equals(publicId)) { return new InputSource(getClass().getResourceAsStream( "/com/jsftoolkit/gen/facelet-taglib_1_0.dtd")); } return null; } }); XPathFactory xpathFactory = XPathFactory.newInstance(); xpathFactory.setXPathVariableResolver(new XPathVariableResolver() { public String resolveVariable(QName variableName) { return vars.get().get(variableName.getLocalPart()); } }); firstComponent = xpathFactory.newXPath().compile( "/faces-config/component[1]"); firstRenderer = xpathFactory.newXPath().compile( "/faces-config/render-kit/renderer[1]"); renderKit = xpathFactory.newXPath().compile( "/faces-config/render-kit[1]"); existingComponent = xpathFactory .newXPath() .compile( "/faces-config/component" + "[child::component-type[normalize-space()=$type]" + " and child::component-class[normalize-space()=$class]]"); existingRenderer = xpathFactory .newXPath() .compile( "/faces-config/render-kit/renderer" + "[child::component-family[normalize-space()=$family] " + "and child::renderer-type[normalize-space()=$rtype]]"); existingTag = xpathFactory.newXPath().compile( "/facelet-taglib/tag[child::tag-name[normalize-space()=$tag]]"); componentElement = xpathFactory.newXPath().compile("component[1]"); existingTldTag = xpathFactory.newXPath().compile( "/taglib/tag[child::name[normalize-space()=$tag]]"); attributeElement = xpathFactory.newXPath().compile( "attribute[child::name[normalize-space()=$name]][1]"); } /** * * @return the configuration updater instance. * @throws XPathExpressionException * @throws ParserConfigurationException */ public synchronized static ConfigurationUpdater getInstance() throws XPathExpressionException, ParserConfigurationException { if (instance == null) { instance = new ConfigurationUpdater(); } return instance; } /** * Updates each relevant configuration file for the given component. If the * file does not exist, it will be created. * * @param info * @throws ParserConfigurationException * @throws SAXException * @throws IOException * @throws XPathExpressionException * @throws IntrospectionException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void updateAll(ComponentInfo info) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException, IntrospectionException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { // try to create each file (if necessary) and update it for the // component String facesConfig = info.getConfig().getFacesConfig(); if (null != facesConfig) { File file = getFacesConfig(facesConfig); System.out.println("Updating faces-config " + file); updateFacesConfig(new FileInputStream(file), new DeferedFileOutputStream(file), info); } String taglibXml = info.getConfig().getTaglibXml(); String namespace = info.getConfig().getNamespace(); if (null != taglibXml) { File file = getTaglib(namespace, taglibXml); System.out.println("Updating taglib.xml " + file); updateTaglibXml(new FileInputStream(file), new DeferedFileOutputStream(file), info); } String tldFile = info.getConfig().getTldFile(); if (null != tldFile) { String shortName = info.getConfig().getLibraryShortName(); File file = getTld(tldFile, namespace, shortName); System.out.println("Updating TLD " + file); updateTld(new FileInputStream(file), new DeferedFileOutputStream( file), info); } } public File getTld(String tldFile, String namespace, String shortName) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { File file = new File(tldFile); if (!file.exists() && Utils.createFileAndParents(file)) { createTld(new DeferedFileOutputStream(file), namespace, shortName); } return file; } public File getTaglib(String namespace, String taglibXml) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { File file = new File(taglibXml); if (!file.exists() && Utils.createFileAndParents(file)) { createFaceletsTaglib(new DeferedFileOutputStream(file), namespace); } return file; } public File getFacesConfig(String facesConfig) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { File file = new File(facesConfig); if (!file.exists() && Utils.createFileAndParents(file)) { createFacesConfig(new DeferedFileOutputStream(file)); } return file; } /** * Parses faces-config.xml from in, adds the given components and writes the * updated file to out. * * @param in * @param out * @param components * @throws ParserConfigurationException * @throws SAXException * @throws IOException * @throws XPathExpressionException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void updateFacesConfig(InputStream in, OutputStream out, ComponentInfo... components) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Utils.write( domUpdateFacesConfig(documentBuilder.parse(in), components), out); } public void updateFacesConfig(File facesConfig, ComponentInfo... infos) throws XPathExpressionException, FileNotFoundException, ParserConfigurationException, SAXException, IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { System.out.println("Updating faces-config " + facesConfig); updateFacesConfig(new FileInputStream(facesConfig), new DeferedFileOutputStream(facesConfig), infos); } /** * * @param facesConfig * the parsed faces-config.xml * @param components * the components to add * @return * @throws XPathExpressionException */ public Document domUpdateFacesConfig(Document facesConfig, ComponentInfo... components) throws XPathExpressionException { Element root = facesConfig.getDocumentElement(); for (ComponentInfo info : components) { // prepare the variables Map map = vars.get(); map.clear(); map.put("type", info.getType()); map.put("rtype", info.getRendererType()); map.put("family", info.getFamily()); String registerClass = info.getConfig().getRegisterClass(); map.put("class", registerClass); System.out.println("Registering component class: " + registerClass); // find/create the component node Element e = findOrCreateElement(facesConfig, root, existingComponent, "component", firstComponent); // update/create the type and class elements setElementValue(facesConfig, e, "component-type", info.getType()); setElementValue(facesConfig, e, "component-class", registerClass); Element rkElem = (Element) findOrCreateElement(facesConfig, root, renderKit, "render-kit", null); // find/create the renderer e = findOrCreateElement(facesConfig, rkElem, existingRenderer, "renderer", firstRenderer); // update/create the renderer mapping elements setElementValue(facesConfig, e, "component-family", info .getFamily()); setElementValue(facesConfig, e, "renderer-type", info .getRendererType()); String registerRenderer = info.getConfig().getRegisterRenderer(); System.out.println("Registering renderer: " + registerRenderer); setElementValue(facesConfig, e, "renderer-class", registerRenderer); } return facesConfig; } public void updateTaglibXml(File taglib, ComponentInfo[] infos) throws XPathExpressionException, FileNotFoundException, SAXException, IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { System.out.println("Updating taglib.xml " + taglib); updateTaglibXml(new FileInputStream(taglib), new DeferedFileOutputStream(taglib), infos); } /** * Updates the taglib.xml for the given components. * * @param in * @param out * @param components * @throws SAXException * @throws IOException * @throws XPathExpressionException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void updateTaglibXml(InputStream in, OutputStream out, ComponentInfo... components) throws SAXException, IOException, XPathExpressionException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Utils.write(domUpdateTaglibXml(documentBuilder.parse(in), components), out); } /** * Updates the taglib.xml for the given components. * * @param taglib * @param components * @return * @throws XPathExpressionException */ public Document domUpdateTaglibXml(Document taglib, ComponentInfo... components) throws XPathExpressionException { Element root = taglib.getDocumentElement(); for (ComponentInfo info : components) { vars.get().clear(); vars.get().put("tag", info.getConfig().getTagName()); // set the tag name Element tag = findOrCreateElement(taglib, root, existingTag, "tag", null); setElementValue(taglib, tag, "tag-name", info.getConfig() .getTagName()); // get the component element Element component = findOrCreateElement(taglib, tag, componentElement, "component", null); // set the types setElementValue(taglib, component, "component-type", info.getType()); setElementValue(taglib, component, "renderer-type", info .getRendererType()); } return taglib; } /** * Updates the TLD for the given components. * * @param in * @param out * @param components * @throws SAXException * @throws IOException * @throws XPathExpressionException * @throws IntrospectionException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void updateTld(InputStream in, OutputStream out, ComponentInfo... components) throws SAXException, IOException, XPathExpressionException, IntrospectionException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Utils.write(domUpdateTld(documentBuilder.parse(in), components), out); } public void updateTld(File file, ComponentInfo... components) throws SAXException, IOException, XPathExpressionException, IntrospectionException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { System.out.println("Updating TLD " + file); updateTld(new FileInputStream(file), new DeferedFileOutputStream( file), components); } /** * Updates the TLD for the given components. * * @param taglib * @param components * @return * @throws XPathExpressionException * @throws IntrospectionException */ public Document domUpdateTld(Document taglib, ComponentInfo... components) throws XPathExpressionException, IntrospectionException { Element root = taglib.getDocumentElement(); for (ComponentInfo info : components) { vars.get().clear(); vars.get().put("tag", info.getConfig().getTagName()); Element tag = findOrCreateElement(taglib, root, existingTldTag, "tag", null); setElementValue(taglib, tag, "name", info.getConfig().getTagName()); setElementValue(taglib, tag, "tag-class", info.getTag() .getCannonicalClassName()); setElementValue(taglib, tag, "body-content", "JSP"); // We have to generate a whole attribute element for every // single component and renderer attribute. // There is no inheritance in TLD files. JSP sucks. // get the attributes from the tag super-class for (PropertyDescriptor pd : info.getTag().getPropertyDescriptors()) { createOrUpdateAttrib(taglib, tag, pd.getName(), false); } // write all the properties from ComponentInfo for (PropertyInfo pinfo : info.getProperties().values()) { createOrUpdateAttrib(taglib, tag, pinfo.getName(), pinfo .isRequired()); } for (String attrib : info.getRenderer().getAttribs()) { createOrUpdateAttrib(taglib, tag, attrib, false); } // write the standard properties (binding, id & rendered) createOrUpdateAttrib(taglib, tag, "binding", false); createOrUpdateAttrib(taglib, tag, "id", false); createOrUpdateAttrib(taglib, tag, "rendered", false); } return taglib; } /** * Writes an empty faces-config.xml to the given stream. * * @param out * @throws IOException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void createFacesConfig(OutputStream out) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Utils.write(domCreateFacesConfig(), out); } /** * * @return an empty faces-config Document */ public Document domCreateFacesConfig() { Document doc = documentBuilder.newDocument(); doc.appendChild(doc.createElement("faces-config")); doc.normalizeDocument(); return doc; } /** * Creates an empty facelets taglib for the given namespace. * * @param out * @param namespace * @throws IOException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void createFaceletsTaglib(OutputStream out, String namespace) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Utils.write(domCreateFaceletsTaglib(namespace), out); // TODO stupid taglib.xmls require a DOCTYPE, but Dom wont let us add // one, so we need to rewrite the file, injecting the doctype. } /** * * @param namespace * @return an empty taglib.xml document. */ public Document domCreateFaceletsTaglib(String namespace) { Document doc = documentBuilder.newDocument(); Element root = doc.createElement("facelet-taglib"); doc.appendChild(root); root.appendChild(newElement(doc, "namespace", namespace)); doc.normalizeDocument(); return doc; } /** * Creates and empty TLD file. * * @param out * @param uri * @param shortName * @throws IOException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws ClassCastException */ public void createTld(OutputStream out, String uri, String shortName) throws IOException, ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException { Document doc = domCreateTld(uri, shortName); Utils.write(doc, out); } /** * * @param uri * @param shortName * @return and empty TLD */ public Document domCreateTld(String uri, String shortName) { Document doc = documentBuilder.newDocument(); Element root = doc.createElement("taglib"); doc.appendChild(root); root.appendChild(newElement(doc, "tlib-version", "1.1")); root.appendChild(newElement(doc, "jsp-version", "2.1")); root.appendChild(newElement(doc, "short-name", shortName)); root.appendChild(newElement(doc, "uri", uri)); doc.normalizeDocument(); return doc; } /** * Create the given element and set it's content. * * @param doc * @param tagName * @param textContent * @return */ protected Element newElement(Document doc, String tagName, String textContent) { Element e = doc.createElement(tagName); e.setTextContent(textContent); return e; } /** * Updates a TLD tag attribute element. * * @param taglib * @param tag * @param attrib * @param required * @throws XPathExpressionException */ protected void createOrUpdateAttrib(Document taglib, Element tag, String attrib, boolean required) throws XPathExpressionException { vars.get().put("name", attrib); Element a = findOrCreateElement(taglib, tag, attributeElement, "attribute", null); setElementValue(taglib, a, "name", attrib); setElementValue(taglib, a, "required", Boolean.toString(required)); // TODO add type metadata } /** * * @param doc * the document being parsed * @param pathExpression * the xpath to find the node * @param elementName * the name of the element tag * @param siblingExpression * the xpath for finding the node that this element should be * inserted before (or null if there isn't one) * @return the element * @throws XPathExpressionException */ protected Element findOrCreateElement(Document doc, Element parent, XPathExpression pathExpression, String elementName, XPathExpression siblingExpression) throws XPathExpressionException { Node found = findNode(parent, pathExpression); Element e; if (found == null) { e = doc.createElement(elementName); parent.insertBefore(e, findNode(parent, siblingExpression)); } else { e = (Element) found; } return e; } /** * Sets the text value of the child element with the given tag name, * creating it if it doesn't exist. * * @param doc * @param parent * @param tagName * @param value */ protected void setElementValue(Document doc, Element parent, String tagName, String value) { NodeList elements = parent.getElementsByTagName(tagName); if (elements.getLength() > 0) { Node item = elements.item(0); if (value == null) { item.getParentNode().removeChild(item); } else { item.setTextContent(value); } } else { parent.appendChild(newElement(doc, tagName, value)); } } /** * * @param ctx * @param expression * @return the first node to match expression, relative to ctx * @throws XPathExpressionException */ public static Node findNode(Element ctx, XPathExpression expression) throws XPathExpressionException { return expression == null ? null : (Node) expression.evaluate(ctx, XPathConstants.NODE); } /** * * @param ctx * @param expression * @return the list of nodes that match expression relative to ctx * @throws XPathExpressionException */ public static NodeList find(Element ctx, XPathExpression expression) throws XPathExpressionException { return (NodeList) expression.evaluate(ctx, XPathConstants.NODESET); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy