com.liferay.faces.generator.Generator.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.faces.generator.Generator.java

Source

/**
 * Copyright (c) 2000-2016 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */
package com.liferay.faces.generator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FileUtils;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

import freemarker.ext.dom.NodeModel;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

/**
 * @author  Kyle Stiemann
 */
public final class Generator {

    private Configuration configuration;
    private DocumentBuilder documentBuilder;
    private Map<String, Tag> commonComponentsMap;

    private Generator() {

        this.configuration = createConfiguration();
        this.documentBuilder = createDocumentBuilder();
        this.commonComponentsMap = createCommonComponentsMap(documentBuilder);
    }

    public static void main(String[] args) throws FileNotFoundException, IOException {

        Generator generator = new Generator();

        for (String arg : args) {
            generator.generateComponents(arg);
        }
    }

    private void addExtensionAttributes(Tag tag, Map<String, Tag> tagMap, Document document) {

        List<String> extendsTagsNames = tag.getExtendsTags();

        for (String extendedTagName : extendsTagsNames) {

            Tag extendedTag = tagMap.get(extendedTagName);

            if ((extendedTag == null) && extendedTagName.endsWith("Inherited")) {

                int extendedTagNameLength = extendedTagName.length();
                int inheritedLength = "Inherited".length();
                String inheritedExtendedTagName = extendedTagName.substring(0,
                        extendedTagNameLength - inheritedLength);
                extendedTag = tagMap.get(inheritedExtendedTagName);
            }

            if (extendedTag == null) {

                String tagName = tag.getTagName();
                throw new NoSuchElementException(tagName + " extends non-existent tag " + extendedTagName);
            }

            addExtensionAttributes(extendedTag, tagMap, document);
            tag.addExtendedComponentAttributes(extendedTag, document, extendedTagName.endsWith("Inherited"));
        }
    }

    private Map<String, Tag> createCommonComponentsMap(DocumentBuilder documentBuilder) {

        InputStream commonComponentsInputStream = getClass().getResourceAsStream("/common-tags.xml");
        Map<String, Tag> commonComponentsMap = new HashMap<String, Tag>();
        Document document = null;

        try {
            document = documentBuilder.parse(commonComponentsInputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        Node documentNode = document.getDocumentElement();
        NodeList childNodes = documentNode.getChildNodes();
        int totalChildNodes = childNodes.getLength();

        for (int i = 0; i < totalChildNodes; i++) {

            Node childNode = childNodes.item(i);
            String nodeName = childNode.getNodeName();

            if (nodeName.equals("tag")) {

                Tag tag = new Tag(childNode);
                commonComponentsMap.put(tag.getTagName(), tag);
            }
        }

        Set<Entry<String, Tag>> commonComponentsEntrySet = commonComponentsMap.entrySet();

        for (Entry<String, Tag> commonTagEntry : commonComponentsEntrySet) {

            Tag tag = commonTagEntry.getValue();
            addExtensionAttributes(tag, commonComponentsMap, document);
            tag.removeExtendsTags();
        }

        return Collections.unmodifiableMap(commonComponentsMap);
    }

    private Configuration createConfiguration() {

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
        configuration.setClassForTemplateLoading(getClass(), "/templates");
        configuration.setTemplateUpdateDelayMilliseconds(Long.MAX_VALUE);
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);

        return configuration;
    }

    private DocumentBuilder createDocumentBuilder() {

        DocumentBuilder documentBuilder;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

        try {
            documentBuilder = dbFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        return documentBuilder;
    }

    private void generateComponentFile(String directoryPath, String shortNamespace, Tag tag,
            String componentFileType, Map<String, Object> freemarkerProperties) throws IOException {

        StringBuilder componentFilePathStringBuilder = new StringBuilder();
        componentFilePathStringBuilder.append(directoryPath);
        componentFilePathStringBuilder.append("/");
        componentFilePathStringBuilder.append(shortNamespace);
        componentFilePathStringBuilder.append("/component/");

        String lowerCaseTagName = tag.getTagName().toLowerCase();
        componentFilePathStringBuilder.append(lowerCaseTagName);
        componentFilePathStringBuilder.append("/");

        if (componentFileType.contains("Renderer")) {
            componentFilePathStringBuilder.append("internal/");
        }

        String tagName = tag.getTagName();
        String capitalizedTagName = tagName.substring(0, 1).toUpperCase() + tagName.substring(1);
        componentFilePathStringBuilder.append(capitalizedTagName);

        String componentFileSuffix = componentFileType.replace("Component", "");
        componentFilePathStringBuilder.append(componentFileSuffix);
        componentFilePathStringBuilder.append(".java");

        String templateName = componentFileType + ".java.ftl";

        generateFile(componentFilePathStringBuilder.toString(), freemarkerProperties, templateName,
                componentFileType.contains("Base"));
    }

    private void generateComponents(String tagsFilePath) throws FileNotFoundException, IOException {

        File file = new File(tagsFilePath);

        if (!file.exists()) {
            throw new FileNotFoundException(tagsFilePath + " not found.");
        }

        if (!file.isFile()) {
            throw new IllegalArgumentException(tagsFilePath + " is not a file.");
        }

        if (!file.canRead()) {
            throw new IllegalArgumentException(tagsFilePath + " is not a readable file.");
        }

        String fileName = file.getName();
        String shortNamespace = fileName.replace("-tags.xml", "");
        Map<String, Object> freemarkerProperties = new HashMap<String, Object>();
        freemarkerProperties.put("shortNamespace", shortNamespace);

        Document document = null;

        try {
            document = documentBuilder.parse(file);
        } catch (SAXException e) {
            throw new IllegalArgumentException(tagsFilePath + " is not a valid xml file.", e);
        }

        Map<String, Tag> tagMap = new HashMap<String, Tag>();
        tagMap.putAll(commonComponentsMap);

        boolean taglibExtensionElementExists = false;
        String componentOutpoutDirectoryPath = null;
        String componentInternalOutpoutDirectoryPath = null;
        String taglibXMLOuputDirectoryPath = null;
        Node documentNode = document.getDocumentElement();
        NodeList childNodes = documentNode.getChildNodes();
        int totalChildNodes = childNodes.getLength();

        for (int i = 0; i < totalChildNodes; i++) {

            Node childNode = childNodes.item(i);
            String nodeName = childNode.getNodeName();

            if (nodeName.equals("tag")) {

                Tag tag = new Tag(childNode);
                tagMap.put(tag.getTagName(), tag);
            } else if (nodeName.equals("taglib-extension")) {

                taglibExtensionElementExists = true;
                componentOutpoutDirectoryPath = GeneratorUtil.getNodeContents("component-output-directory",
                        childNode);

                if ((componentOutpoutDirectoryPath == null) || componentOutpoutDirectoryPath.equals("")) {
                    throw new NullPointerException("<component-output-directory> must be specified.");
                }

                componentInternalOutpoutDirectoryPath = GeneratorUtil
                        .getNodeContents("component-internal-output-directory", childNode);

                if ((componentInternalOutpoutDirectoryPath == null)
                        || componentInternalOutpoutDirectoryPath.equals("")) {
                    componentInternalOutpoutDirectoryPath = componentOutpoutDirectoryPath;
                }

                taglibXMLOuputDirectoryPath = GeneratorUtil.getNodeContents("taglib-xml-output-directory",
                        childNode);

                if ((taglibXMLOuputDirectoryPath == null) || taglibXMLOuputDirectoryPath.equals("")) {
                    throw new NullPointerException("<taglib-xml-output-directory> must be specified.");
                }

                String authorsString = GeneratorUtil.getNodeContents("authors", childNode);

                if ((authorsString != null) && !authorsString.equals("")) {

                    String[] authorsArray = authorsString.split(",");
                    List<String> authors = new ArrayList<String>();

                    for (String author : authorsArray) {

                        String trimmedAuthor = author.trim();
                        authors.add(trimmedAuthor);
                    }

                    if (!authors.isEmpty()) {
                        freemarkerProperties.put("authors", authors);
                    }
                }

                String copyrightYear = GeneratorUtil.getNodeContents("copyright-year", childNode);

                if ((copyrightYear == null) || copyrightYear.equals("")) {

                    GregorianCalendar calendar = new GregorianCalendar();
                    int year = calendar.get(Calendar.YEAR);
                    copyrightYear = String.valueOf(year);
                }

                freemarkerProperties.put("copyrightYear", copyrightYear);

                String defaultSince = GeneratorUtil.getNodeContents("default-since", childNode);

                if (defaultSince == null) {
                    defaultSince = "1.0.0";
                }

                freemarkerProperties.put("defaultSince", defaultSince);

                String facesSpecVersion = GeneratorUtil.getNodeContents("faces-spec-version", childNode);

                if ((facesSpecVersion == null) || facesSpecVersion.equals("")) {
                    facesSpecVersion = "2.0";
                }

                freemarkerProperties.put("facesSpecVersion", facesSpecVersion);
            }
        }

        if (!taglibExtensionElementExists) {
            throw new NullPointerException("<taglib-extension> must be specified.");
        }

        Set<Entry<String, Tag>> tagMapEntrySet = tagMap.entrySet();

        for (Entry<String, Tag> tagEntry : tagMapEntrySet) {

            Tag tag = (Tag) tagEntry.getValue();
            addExtensionAttributes(tag, tagMap, document);

            if (tag.isGenerateJava() && (tag.isGenerateComponent() || tag.isGenerateRenderer())) {

                NodeModel tagNodeModel = tag.getTagNodeModel();
                freemarkerProperties.put("tag", tagNodeModel);

                if (tag.isGenerateComponent()) {

                    generateComponentFile(componentOutpoutDirectoryPath, shortNamespace, tag, "Component",
                            freemarkerProperties);
                    generateComponentFile(componentOutpoutDirectoryPath, shortNamespace, tag, "ComponentBase",
                            freemarkerProperties);
                }

                if (tag.isGenerateRenderer()) {

                    generateComponentFile(componentInternalOutpoutDirectoryPath, shortNamespace, tag,
                            "ComponentRenderer", freemarkerProperties);
                    generateComponentFile(componentInternalOutpoutDirectoryPath, shortNamespace, tag,
                            "ComponentRendererBase", freemarkerProperties);
                }
            }
        }

        freemarkerProperties.remove("tag");

        NodeModel tagsDocumentNodeModel = NodeModel.wrap(document);
        freemarkerProperties.put("tagsDocument", tagsDocumentNodeModel);

        StringBuilder taglibXMLFilePathStringBuilder = new StringBuilder();
        taglibXMLFilePathStringBuilder.append(taglibXMLOuputDirectoryPath);
        taglibXMLFilePathStringBuilder.append("/");
        taglibXMLFilePathStringBuilder.append(shortNamespace);
        taglibXMLFilePathStringBuilder.append(".taglib.xml");

        generateFile(taglibXMLFilePathStringBuilder.toString(), freemarkerProperties, "taglib.xml.ftl", true);
    }

    private void generateFile(String filePath, Map<String, Object> freemarkerProperties, String templateName,
            boolean overwriteFile) throws IOException {

        File file = new File(filePath);
        boolean fileExists = file.exists();

        if (!fileExists || overwriteFile) {

            StringWriter stringWriter = new StringWriter();
            Template template = null;

            try {
                template = configuration.getTemplate(templateName);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            try {
                template.process(freemarkerProperties, stringWriter);
            } catch (TemplateException e) {
                throw new RuntimeException(e);
            }

            String templateResults = stringWriter.toString();
            String fileContents = null;

            if (fileExists) {
                fileContents = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
            }

            if (!templateResults.equals(fileContents)) {

                System.out.println("Writing " + file);
                FileUtils.writeStringToFile(file, templateResults, StandardCharsets.UTF_8);
            }
        }
    }
}