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

com.buschmais.jqassistant.plugin.javaee6.impl.scanner.JsfFaceletScannerPlugin Maven / Gradle / Ivy

Go to download

Plugin for jQAssistant to be able to scan and to analyze Java EE 6 related artifacts.

There is a newer version: 1.12.2
Show newest version
package com.buschmais.jqassistant.plugin.javaee6.impl.scanner;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.regex.Pattern;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import com.buschmais.jqassistant.core.scanner.api.Scanner;
import com.buschmais.jqassistant.core.scanner.api.ScannerContext;
import com.buschmais.jqassistant.core.scanner.api.ScannerPlugin.Requires;
import com.buschmais.jqassistant.core.scanner.api.Scope;
import com.buschmais.jqassistant.core.store.api.Store;
import com.buschmais.jqassistant.plugin.common.api.model.FileDescriptor;
import com.buschmais.jqassistant.plugin.common.api.scanner.AbstractScannerPlugin;
import com.buschmais.jqassistant.plugin.common.api.scanner.FileResolver;
import com.buschmais.jqassistant.plugin.common.api.scanner.filesystem.FileResource;
import com.buschmais.jqassistant.plugin.javaee6.api.model.JsfFaceletDescriptor;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Scans JSF template files and sets relationships between them.
 *
 * @author [email protected]
 */
@Requires(FileDescriptor.class)
public class JsfFaceletScannerPlugin extends AbstractScannerPlugin {

    private static final Logger LOGGER = LoggerFactory.getLogger(JsfFaceletScannerPlugin.class);

    private static final String DEFAULT_FILE_PATTERN = ".*\\.jspx";
    private static final String PROPERTY_NAME_FILE_PATTERN = "facelet.file.pattern";

    private DocumentBuilder documentBuilder;
    private Pattern filePattern;
    private XPath xPath;

    /** {@inheritDoc} */
    @Override
    public void initialize() {
        // initialize xpath
        XPathFactory xPathfactory = XPathFactory.newInstance();
        xPath = xPathfactory.newXPath();
        xPath.setNamespaceContext(new NamespaceContext() {

            @Override
            @SuppressWarnings("rawtypes")
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }

            @Override
            public String getPrefix(String namespaceURI) {
                return null;
            }

            @Override
            public String getNamespaceURI(String prefix) {
                if (prefix != null) {
                    switch (prefix) {
                    case XMLConstants.DEFAULT_NS_PREFIX:
                        return "http://www.w3.org/1999/xhtml";
                    case "ui":
                        return "http://java.sun.com/jsf/facelets";
                    case "h":
                        return "http://java.sun.com/jsf/html";
                    case "f":
                        return "http://java.sun.com/jsf/core";
                    }
                }
                return XMLConstants.NULL_NS_URI;
            }
        });

        // initialize DocumentBuilder
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setValidating(false);
        try {
            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        } catch (ParserConfigurationException e) {
            LOGGER.warn("Cannot set features of document builder factory.", e);
        }
        try {
            documentBuilder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new IllegalStateException("Cannot create document builder.", e);
        }

    } // end method initialize

    @Override
    public void configure() {
        if (getProperties().containsKey(PROPERTY_NAME_FILE_PATTERN)) {
            filePattern = Pattern.compile(getProperties().get(PROPERTY_NAME_FILE_PATTERN).toString());
        } else {
            filePattern = Pattern.compile(DEFAULT_FILE_PATTERN);
        }
    }

    /** {@inheritDoc} */
    @Override
    public boolean accepts(FileResource item, String path, Scope scope) throws IOException {
        return filePattern.matcher(path).matches();
    }

    /** {@inheritDoc} */
    @Override
    public JsfFaceletDescriptor scan(FileResource item, String path, Scope scope, Scanner scanner) throws IOException {
        ScannerContext context = scanner.getContext();
        Store store = context.getStore();
        FileDescriptor fileDescriptor = context.getCurrentDescriptor();
        JsfFaceletDescriptor currentDescriptor = store.addDescriptorType(fileDescriptor, JsfFaceletDescriptor.class);

        try {
            // read the xml file
            Document doc = getDocument(item);
            // find includes
            NodeList nodeList = (NodeList) getXPath().evaluate("//ui:include", doc, XPathConstants.NODESET);

            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                String includeSrc = node.getAttributes().getNamedItem("src").getNodeValue();
                JsfFaceletDescriptor includedJsf = findJsfTemplateDescriptor(path, includeSrc, context);

                if (includedJsf != null) {
                    currentDescriptor.getIncludes().add(includedJsf);
                }
            }

            // find template relationship
            String templateSrc = (String) getXPath().evaluate("//ui:composition/@template", doc, XPathConstants.STRING);

            if (StringUtils.isNotBlank(templateSrc)) {
                currentDescriptor.setTemplate(findJsfTemplateDescriptor(path, templateSrc, context));
            }
        } catch (XPathExpressionException | SAXException e) {
            throw new IOException(e);
        }

        return currentDescriptor;
    } // end method scan

    /**
     * Try to find an existing {@link JsfFaceletDescriptor} with the given
     * parameters.
     *
     * @param templateFqn
     *            full qualified name of the including file
     * @param path
     *            the found path to the included file
     * @param context
     *            The scanner context
     * @return an existing {@link JsfFaceletDescriptor} or a new one if no
     *         descriptor exists.
     */
    private JsfFaceletDescriptor findJsfTemplateDescriptor(String templateFqn, String path, ScannerContext context) {
        String includedFile = absolutifyFilePath(path, templateFqn);
        return getJsfTemplateDescriptor(includedFile, context);
    }

    /**
     * Normalize file paths like the jqassistant core (e.g. replace backslashs,
     * add leading slash).
     *
     * @param path
     *            the path to normalize
     *
     * @return the normalized path
     */
    private String normalizeFilePath(final String path) {
        String normalizedPath = path.replace('\\', '/');

        if (!normalizedPath.startsWith("/")) {
            normalizedPath = "/" + normalizedPath;
        }

        return normalizedPath;
    }

    /**
     * 

* Try to make an absolute path from a relative path and a reference path. *

* *

* Example:
* path - ../../a/b.jspx
* referencePath - c/d/e/f.jspx
* Result: c/a/b.jspx *

* * @param path * the relative path * @param referencePath * the reference file path (should be absolute) * * @return a path absolute path in reference to the second path. */ private String absolutifyFilePath(final String path, final String referencePath) { // can't handle EL-expressions if (isElExpression(path)) { return path; } String normalizedPath; if (!path.startsWith("/")) { Path reference = Paths.get(referencePath); normalizedPath = reference.getParent().resolve(path).normalize().toString(); } else { normalizedPath = Paths.get(path).normalize().toString(); } return normalizeFilePath(normalizedPath); } /** * Parses the xml file with a {@link DocumentBuilder}. * * @param resource * the file to read * * @return a {@link Document} * * @throws SAXException * see {@link DocumentBuilder#parse(java.io.File)} * @throws IOException * see {@link DocumentBuilder#parse(java.io.File)} */ private Document getDocument(FileResource resource) throws SAXException, IOException { return documentBuilder.parse(resource.getFile()); } /** * Tries to find a {@link JsfFaceletDescriptor} in the store with the given * fullFilePath. Creates a new one if no descriptor could be found. * * @param fullFilePath * the file path of the wanted file * @param context * The scanner context. * @return a {@link JsfFaceletDescriptor} representing the wanted file */ private JsfFaceletDescriptor getJsfTemplateDescriptor(String fullFilePath, ScannerContext context) { // can't handle EL-expressions if (isElExpression(fullFilePath)) { return null; } return context.peek(FileResolver.class).require(fullFilePath, JsfFaceletDescriptor.class, context); } /** * If the argument starts with '#{' or '${' it is an EL-expression. * * @param str * input string * * @return true if the argument starts with '#{' or '${', * otherwise * false */ private boolean isElExpression(String str) { return str.startsWith("#{") || str.startsWith("${"); } /** * Lazy getter for {@link XPath} object. * * @return the xpath object. */ private XPath getXPath() { return xPath; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy