| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.myfaces.buildtools.maven2.plugin.faces; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| import javax.xml.stream.XMLOutputFactory; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamWriter; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.sax.SAXSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.parse.ComponentBean; |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.parse.ConverterBean; |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.parse.FacesConfigBean; |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.parse.ValidatorBean; |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.util.FilteredIterator; |
| import org.apache.myfaces.buildtools.maven2.plugin.faces.util.XIncludeFilter; |
| |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.project.MavenProject; |
| |
| import org.codehaus.plexus.util.FileUtils; |
| |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.XMLReader; |
| |
| /** |
| * @version $Id$ |
| * @requiresDependencyResolution compile |
| * @goal generate-facelets-taglibs |
| * @phase generate-sources |
| */ |
| public class GenerateFaceletsTaglibsMojo extends AbstractFacesMojo |
| { |
| /** |
| * Execute the Mojo. |
| */ |
| public void execute() throws MojoExecutionException |
| { |
| try |
| { |
| // always add resources directory to project resource root |
| addResourceRoot(project, generatedResourcesDirectory.getCanonicalPath()); |
| |
| processIndex(project, resourcePath); |
| |
| // taglibs map syntax requires distinct shortNames, |
| // which is a Good Thing! |
| for (Iterator i = taglibs.entrySet().iterator(); i.hasNext(); ) |
| { |
| Map.Entry entry = (Map.Entry)i.next(); |
| String shortName = (String)entry.getKey(); |
| String namespaceURI = (String)entry.getValue(); |
| |
| FacesConfigBean facesConfig = getFacesConfig(); |
| Iterator components = facesConfig.components(); |
| components = new FilteredIterator(components, new SkipFilter()); |
| components = new FilteredIterator(components, new ComponentTagLibraryFilter(namespaceURI, false)); |
| |
| Iterator validators = facesConfig.validators(); |
| validators = new FilteredIterator(validators, new ValidatorTagLibraryFilter(namespaceURI, false)); |
| |
| Iterator converters = facesConfig.converters(); |
| converters = new FilteredIterator(converters, new ConverterTagLibraryFilter(namespaceURI, false)); |
| |
| |
| String targetPath = "META-INF/" + shortName + ".taglib.xml"; |
| File targetFile = new File(generatedResourcesDirectory, targetPath); |
| |
| String configPath = "META-INF/" + shortName + "-base.taglib.xml"; |
| File configFile = new File(configSourceDirectory, configPath); |
| |
| targetFile.delete(); |
| |
| if ((components.hasNext()||validators.hasNext()||converters.hasNext()) |
| && configFile.exists()) |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); |
| XMLStreamWriter stream = outputFactory.createXMLStreamWriter(out); |
| |
| _writeStartTagLibrary(stream, _XINCLUDE_FACELETS_TAG_LIBRARY_DTD); |
| // base goes first |
| stream.writeStartElement("xi", "include", |
| XIncludeFilter.XINCLUDE_NAMESPACE); |
| stream.writeNamespace("xi", XIncludeFilter.XINCLUDE_NAMESPACE); |
| stream.writeAttribute("href", configFile.toURL().toExternalForm()); |
| stream.writeAttribute("xpointer", "/facelet-taglib/*"); |
| stream.writeEndElement(); |
| _writeTags(components, validators, converters, stream); |
| |
| _writeEndTagLibrary(stream); |
| stream.close(); |
| |
| InputStream mergedStream = new ByteArrayInputStream(out.toByteArray()); |
| |
| // expand all the xi:include elements |
| SAXParserFactory saxFactory = SAXParserFactory.newInstance(); |
| saxFactory.setNamespaceAware(true); |
| saxFactory.setValidating(false); |
| SAXParser saxParser = saxFactory.newSAXParser(); |
| XMLReader mergedReader = saxParser.getXMLReader(); |
| mergedReader = new XIncludeFilter(mergedReader, configFile.toURL()); |
| // even with validating=false, DTD is still downloaded so that |
| // any entities contained in the document can be expanded. |
| // the following disables that behavior, also saving the time |
| // spent to parse the DTD |
| mergedReader.setEntityResolver(new EntityResolver() |
| { |
| public InputSource resolveEntity( |
| String publicId, |
| String systemId) |
| { |
| return new InputSource(new ByteArrayInputStream(new byte[0])); |
| } |
| }); |
| InputSource mergedInput = new InputSource(mergedStream); |
| Source mergedSource = new SAXSource(mergedReader, mergedInput); |
| |
| targetFile.delete(); |
| targetFile.getParentFile().mkdirs(); |
| Result mergedResult = new StreamResult(targetFile); |
| |
| TransformerFactory transFactory = TransformerFactory.newInstance(); |
| Transformer identity = transFactory.newTransformer(); |
| identity.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, |
| _FACELETS_TAG_LIBRARY_DOCTYPE_PUBLIC); |
| identity.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, |
| _FACELETS_TAG_LIBRARY_DOCTYPE_SYSTEM); |
| identity.transform(mergedSource, mergedResult); |
| |
| targetFile.setReadOnly(); |
| } |
| else if (components.hasNext()||validators.hasNext()||converters.hasNext()) |
| { |
| targetFile.getParentFile().mkdirs(); |
| OutputStream out = new FileOutputStream(targetFile); |
| XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); |
| XMLStreamWriter stream = outputFactory.createXMLStreamWriter(out); |
| |
| _writeStartTagLibrary(stream, _FACELETS_TAG_LIBRARY_DTD); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("namespace"); |
| stream.writeCharacters(namespaceURI); |
| stream.writeEndElement(); |
| |
| _writeTags(components, validators, converters, stream); |
| _writeEndTagLibrary(stream); |
| stream.close(); |
| } |
| else if (configFile.exists()) |
| { |
| // copy if newer |
| if (configFile.lastModified() > targetFile.lastModified()) |
| { |
| targetFile.delete(); |
| targetFile.getParentFile().mkdirs(); |
| FileUtils.copyFile(configFile, targetFile); |
| targetFile.setReadOnly(); |
| } |
| } |
| |
| getLog().info("Generated " + targetPath); |
| } |
| } |
| catch (XMLStreamException e) |
| { |
| throw new MojoExecutionException("Error during generation", e); |
| } |
| catch (SAXException e) |
| { |
| throw new MojoExecutionException("Error during generation", e); |
| } |
| catch (TransformerException e) |
| { |
| throw new MojoExecutionException("Error during generation", e); |
| } |
| catch (ParserConfigurationException e) |
| { |
| throw new MojoExecutionException("Error during generation", e); |
| } |
| catch (IOException e) |
| { |
| throw new MojoExecutionException("Error during generation", e); |
| } |
| } |
| |
| private void _writeTags(Iterator components, Iterator validators, |
| Iterator converters, XMLStreamWriter stream) |
| throws XMLStreamException |
| { |
| while (components.hasNext()) |
| { |
| ComponentBean component = (ComponentBean)components.next(); |
| _writeTag(stream, component); |
| } |
| while (validators.hasNext()) |
| { |
| _writeValidatorTag(stream, (ValidatorBean) validators.next()); |
| } |
| while (converters.hasNext()) |
| { |
| _writeConverterTag(stream, (ConverterBean) converters.next()); |
| } |
| } |
| |
| private void _writeStartTagLibrary( |
| XMLStreamWriter stream, |
| String dtd) throws XMLStreamException |
| { |
| stream.writeStartDocument("1.0"); |
| stream.writeCharacters("\n"); |
| stream.writeDTD(dtd); |
| stream.writeCharacters("\n"); |
| stream.writeStartElement("facelet-taglib"); |
| stream.writeDefaultNamespace(_FACELETS_NAMESPACE_URI); |
| stream.writeCharacters("\n "); |
| } |
| |
| private void _writeEndTagLibrary( |
| XMLStreamWriter stream) throws XMLStreamException |
| { |
| |
| stream.writeCharacters("\n"); |
| stream.writeEndElement(); |
| stream.writeEndDocument(); |
| } |
| |
| /** |
| * Generates tag library descriptor for parsed component metadata. |
| */ |
| private void _writeTag( |
| XMLStreamWriter stream, |
| ComponentBean component) throws XMLStreamException |
| { |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag-name"); |
| stream.writeCharacters(component.getTagName().getLocalPart()); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("component"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("component-type"); |
| stream.writeCharacters(component.getComponentType()); |
| stream.writeEndElement(); |
| |
| if (component.getRendererType() != null) |
| { |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("renderer-type"); |
| stream.writeCharacters(component.getRendererType()); |
| stream.writeEndElement(); |
| } |
| |
| String tagHandler = component.getTagHandler(); |
| if (tagHandler == null) |
| { |
| tagHandler = faceletHandlerClass; |
| } |
| if (tagHandler != null) |
| { |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("handler-class"); |
| stream.writeCharacters(tagHandler); |
| stream.writeEndElement(); |
| } |
| |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| } |
| |
| /** |
| * Generates tag library descriptor for parsed validator metadata. |
| */ |
| private void _writeValidatorTag( |
| XMLStreamWriter stream, |
| ValidatorBean validator) throws XMLStreamException |
| { |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag-name"); |
| stream.writeCharacters(validator.getTagName().getLocalPart()); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("validator"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("validator-id"); |
| stream.writeCharacters(validator.getValidatorId()); |
| stream.writeEndElement(); |
| |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| } |
| |
| /** |
| * Generates tag library descriptor for parsed converter metadata. |
| */ |
| private void _writeConverterTag( |
| XMLStreamWriter stream, |
| ConverterBean converter) throws XMLStreamException |
| { |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("tag-name"); |
| stream.writeCharacters(converter.getTagName().getLocalPart()); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("converter"); |
| stream.writeCharacters("\n "); |
| stream.writeStartElement("converter-id"); |
| stream.writeCharacters(converter.getConverterId()); |
| stream.writeEndElement(); |
| |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| stream.writeCharacters("\n "); |
| stream.writeEndElement(); |
| } |
| |
| |
| /** |
| * @parameter expression="${project}" |
| * @required |
| * @readonly |
| */ |
| private MavenProject project; |
| |
| /** |
| * @parameter expression="META-INF/maven-faces-plugin/faces-config.xml" |
| * @required |
| * @readonly |
| */ |
| private String resourcePath; |
| |
| /** |
| * @parameter |
| * @required |
| */ |
| private Map taglibs; |
| |
| |
| /** |
| *@parameter |
| */ |
| private String faceletHandlerClass; |
| |
| /** |
| * @parameter expression="src/main/conf" |
| * @required |
| */ |
| private File configSourceDirectory; |
| |
| /** |
| * @parameter expression="${project.build.directory}/maven-faces-plugin/main/resources" |
| * @required |
| */ |
| private File generatedResourcesDirectory; |
| |
| /** |
| * @parameter |
| */ |
| private boolean force; |
| |
| static private final String _FACELETS_NAMESPACE_URI = |
| "http://java.sun.com/JSF/Facelet"; |
| |
| static final private String _FACELETS_TAG_LIBRARY_DOCTYPE_PUBLIC = |
| "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"; |
| |
| static final private String _FACELETS_TAG_LIBRARY_DOCTYPE_SYSTEM = |
| "http://java.sun.com/dtd/facelet-taglib_1_0.dtd"; |
| |
| static final private String _FACELETS_TAG_LIBRARY_DTD = |
| "<!DOCTYPE facelet-taglib PUBLIC \n" + |
| " \"" + _FACELETS_TAG_LIBRARY_DOCTYPE_PUBLIC + "\"\n" + |
| " \"" + _FACELETS_TAG_LIBRARY_DOCTYPE_SYSTEM + "\" >\n"; |
| |
| static final private String _XINCLUDE_FACELETS_TAG_LIBRARY_DTD = |
| "<!DOCTYPE taglib PUBLIC\n" + |
| " \"" + _FACELETS_TAG_LIBRARY_DOCTYPE_PUBLIC + "\"\n" + |
| " \"" + _FACELETS_TAG_LIBRARY_DOCTYPE_SYSTEM + "\" [\n" + |
| " <!ELEMENT xi:include EMPTY>\n" + |
| " <!ATTLIST xi:include\n" + |
| " xmlns:xi CDATA #FIXED \"" + XIncludeFilter.XINCLUDE_NAMESPACE + "\"\n" + |
| " href CDATA #IMPLIED\n" + |
| " xpointer CDATA #IMPLIED>\n" + |
| "]>\n"; |
| } |