org.jahia.utils.osgi.parsers.TldXmlFileParser.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.utils.osgi.parsers.TldXmlFileParser.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2018 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.utils.osgi.parsers;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.jahia.utils.osgi.PackageUtils;
import org.jdom2.Comment;
import org.jdom2.Element;
import org.jdom2.JDOMException;

import java.util.*;

/**
 * A TLD (Java Tag Library definition) file parser
 * @todo This parser doesn't support tag files for the moment, but we really should as we are missing
 * dependencies because of this.
 */
public class TldXmlFileParser extends AbstractXmlFileParser {

    private static Map<String, List<PackageInfo>> knownTransitiveImportPackages;

    static {
        knownTransitiveImportPackages = new HashMap<String, List<PackageInfo>>();
        List<PackageInfo> springServletFormTagTransitiveImport = new ArrayList<PackageInfo>();
        springServletFormTagTransitiveImport.add(new PackageInfo("org.springframework.web.servlet.tags",
                "Jahia Maven plugin built-in hardcoded transitive import list", null));
        knownTransitiveImportPackages.put("org.springframework.web.servlet.tags.form",
                springServletFormTagTransitiveImport);
    }

    public static String getTaglibUri(Element tldRootElement) throws JDOMException {
        boolean hasDefaultNamespace = !StringUtils.isEmpty(tldRootElement.getNamespaceURI());

        Element uriElement = null;
        if (hasDefaultNamespace) {
            uriElement = getElement(tldRootElement, "/xp:taglib/xp:uri");
        } else {
            uriElement = getElement(tldRootElement, "/taglib/uri");
        }
        return uriElement != null ? uriElement.getTextTrim() : null;
    }

    @Override
    public boolean canParse(String fileName) {
        String ext = FilenameUtils.getExtension(fileName).toLowerCase();
        return "tld".equals(ext);
    }

    @Override
    public boolean canParse(String fileName, Element rootElement) {
        return true;
    }

    @Override
    public void parse(String fileName, Element rootElement, String fileParent, boolean externalDependency,
            boolean optionalDependency, String version, ParsingContext parsingContext) throws JDOMException {
        dumpElementNamespaces(rootElement);
        boolean hasDefaultNamespace = !StringUtils.isEmpty(rootElement.getNamespaceURI());
        if (hasDefaultNamespace) {
            getLogger().debug("Using default namespace XPath queries");
        }

        String uri = getTaglibUri(rootElement);
        if (uri == null) {
            getLogger().warn("Couldn't find /taglib/uri tag in " + fileParent + " / " + fileName
                    + ", aborting TLD parsing !");
            return;
        }
        getLogger().debug("Taglib URI=" + uri);
        Set<PackageInfo> taglibPackageSet = parsingContext.getTaglibPackages().get(uri);
        if (taglibPackageSet == null) {
            taglibPackageSet = new TreeSet<PackageInfo>();
        }

        List<Element> tagClassElements = new LinkedList<Element>();
        tagClassElements.addAll(
                getElements(rootElement, hasDefaultNamespace ? "//xp:tag/xp:tag-class" : "//tag/tag-class"));
        tagClassElements.addAll(
                getElements(rootElement, hasDefaultNamespace ? "//xp:tag/xp:tei-class" : "//tag/tei-class"));
        tagClassElements.addAll(getElements(rootElement,
                hasDefaultNamespace ? "//xp:tag/xp:attribute/xp:type" : "//tag/attribute/type"));
        tagClassElements
                .addAll(getElements(rootElement, hasDefaultNamespace ? "//xp:tag/xp:tagclass" : "//tag/tagclass"));
        tagClassElements
                .addAll(getElements(rootElement, hasDefaultNamespace ? "//xp:tag/xp:teiclass" : "//tag/teiclass"));
        for (Element tagClassElement : tagClassElements) {
            getLogger().debug(fileName + " Found tag class " + tagClassElement.getTextTrim() + " package="
                    + PackageUtils.getPackagesFromClass(tagClassElement.getTextTrim(), optionalDependency, version,
                            fileParent + "/" + fileName, parsingContext).toString());
            taglibPackageSet.addAll(PackageUtils.getPackagesFromClass(tagClassElement.getTextTrim(),
                    optionalDependency, version, fileParent + "/" + fileName, parsingContext));
        }

        // Parsing function class
        List<Element> functionClassElements = null;
        if (hasDefaultNamespace) {
            functionClassElements = getElements(rootElement, "//xp:function/xp:function-class");
        } else {
            functionClassElements = getElements(rootElement, "//function/function-class");
        }
        for (Element functionClassElement : functionClassElements) {
            getLogger()
                    .debug(fileName + " Found function class " + functionClassElement.getTextTrim() + " package="
                            + PackageUtils.getPackagesFromClass(functionClassElement.getTextTrim(),
                                    optionalDependency, version, fileParent + "/" + fileName, parsingContext)
                                    .toString());
            taglibPackageSet.addAll(PackageUtils.getPackagesFromClass(functionClassElement.getTextTrim(),
                    optionalDependency, version, fileParent + "/" + fileName, parsingContext));
        }

        // Parsing function signature
        for (Element functionSignatureElement : getElements(rootElement,
                hasDefaultNamespace ? "//xp:function/xp:function-signature" : "//function/function-signature")) {
            List<PackageInfo> pkgs = getPackagesFromFunctionSignature(functionSignatureElement.getTextTrim(),
                    fileParent + "/" + fileName, optionalDependency, version, parsingContext);
            if (pkgs != null && !pkgs.isEmpty()) {
                getLogger().debug(
                        fileName + " Found packages in function signature " + functionSignatureElement.getTextTrim()
                                + " packages=[" + StringUtils.join(pkgs, ", ") + "]");
                taglibPackageSet.addAll(pkgs);
            }
        }

        // Parsing a special "hint" in comments
        for (Object comment : selectNodes(rootElement, "//comment()")) {
            if (comment instanceof Comment) {
                String text = ((Comment) comment).getText();
                List<PackageInfo> pkgs = getPackagesFromTagFileComment(text, fileParent + "/" + fileName,
                        parsingContext);
                if (pkgs != null && !pkgs.isEmpty()) {
                    getLogger().debug(fileName + " Found import packages hint in comment " + text + " packages=["
                            + StringUtils.join(pkgs, ", ") + "]");
                    taglibPackageSet.addAll(pkgs);
                }
            }
        }

        // Parse tag files
        for (Element tagFilePathElement : getElements(rootElement,
                hasDefaultNamespace ? "//xp:tag-file/xp:path" : "//tag-file/path")) {
            String tagFilePath = tagFilePathElement.getTextTrim();
            if (tagFilePath.startsWith("/")) {
                tagFilePath = tagFilePath.substring(1);
            }
            getLogger().debug("Adding tag file to be parsed later in the process: " + tagFilePath);
            parsingContext.addAdditionalFileToParse(tagFilePath);
        }

        Set<PackageInfo> effectivePackages = new TreeSet<PackageInfo>(taglibPackageSet);
        for (PackageInfo pkg : taglibPackageSet) {
            if (knownTransitiveImportPackages.containsKey(pkg.getName())) {
                effectivePackages.addAll(knownTransitiveImportPackages.get(pkg.getName()));
            }
        }

        parsingContext.putTaglibPackages(uri, effectivePackages);
        parsingContext.putExternalTaglib(uri, externalDependency);
    }

    private List<PackageInfo> getPackagesFromTagFileComment(String text, String sourceLocation,
            ParsingContext parsingContext) {
        if (text == null || !text.contains("Import-Package:")) {
            return null;
        }

        List<PackageInfo> pkgs = null;
        String[] tokens = StringUtils.split(StringUtils.replace(text, "Import-Package:", ""), "\n\r \t,");
        for (String token : tokens) {
            if (token.indexOf('.') != -1 && !token.startsWith("java.lang")) {
                if (pkgs == null) {
                    pkgs = new LinkedList<PackageInfo>();
                }
                pkgs.add(new PackageInfo(token, sourceLocation, parsingContext));
            }
        }

        return pkgs;
    }

    private List<PackageInfo> getPackagesFromFunctionSignature(String signature, String sourceLocation,
            boolean optionalDependency, String version, ParsingContext parsingContext) {
        List<PackageInfo> pkgs = null;
        String[] tokens = StringUtils.split(signature, "\n\r \t,()");
        for (String token : tokens) {
            if (token.indexOf('.') != -1 && !token.startsWith("java.lang")) {
                if (pkgs == null) {
                    pkgs = new LinkedList<PackageInfo>();
                }
                pkgs.addAll(PackageUtils.getPackagesFromClass(token, optionalDependency, version, sourceLocation,
                        parsingContext));
            }
        }

        return pkgs;
    }
}