org.nuxeo.ecm.jsf2.migration.impl.MigrationServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.jsf2.migration.impl.MigrationServiceImpl.java

Source

/*
 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * 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.
 *
 * Contributors:
 *     <a href="mailto:glefevre@nuxeo.com">Gildas</a>
 */
package org.nuxeo.ecm.jsf2.migration.impl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jaxen.JaxenException;
import org.nuxeo.ecm.jsf2.migration.api.MigrationService;
import org.nuxeo.ecm.jsf2.migration.enumeration.EnumTypeMigration;
import org.nuxeo.ecm.jsf2.migration.parser.RuleParser;
import org.nuxeo.ecm.jsf2.migration.report.FileReport;

/**
 * Implementation of the services to help the migration to JSF 2.
 *
 * @since 5.9.6
 */
public class MigrationServiceImpl implements MigrationService {

    private static Log logger = LogFactory.getLog(MigrationServiceImpl.class);

    private static final String FILE_EXTENSION = "xhtml";

    private static final String NOTHING_MESSAGE = "file.migration.nothing.message";

    private static final String SUFFIX_DETAILED_MESSAGE = ".detailed";

    private static final String SUFFIX_SUMMARIZED_MESSAGE = ".summarized";

    protected static Set<String> nuxeoTemplates;

    protected static Set<String> nuxeoTemplatesCompletePath;

    protected static Set<String> nuxeoCompatTemplates;

    protected static Set<String> nuxeoCompatTemplatesCompletePath;

    @Override
    public List<File> getAllXhtmlFiles(File root) {
        List<File> listFiles = new ArrayList<File>();

        // Parse all files in the directory
        for (File children : root.listFiles()) {
            if (children.isDirectory()) {
                listFiles.addAll(getAllXhtmlFiles(children));
            }
            if (children.isFile()) {
                String extension = FilenameUtils.getExtension(children.getName());
                if (FILE_EXTENSION.equals(extension)) {
                    listFiles.add(children);
                }
            }
        }

        return listFiles;
    }

    @Override
    public void analyzeProject(File report, List<File> listFiles, boolean doMigration, boolean format)
            throws IOException {
        // If the file does not exist, it is created
        if (!report.exists()) {
            report.createNewFile();
        }

        PrintWriter printWriter = new PrintWriter(report);
        printWriter.append("##############################\n");
        printWriter.append("# Migration report for JSF 2 #\n");
        printWriter.append("##############################\n\n");

        List<FileReport> listReports = new ArrayList<FileReport>();
        for (File file : listFiles) {
            try {
                listReports.add(analyzeFile(file, true, doMigration, format));
            } catch (DocumentException ex) {
                System.out.println(String.format("Error while reading file %s.", file.getName()));
                System.out.println(ex.getMessage());
            } catch (JaxenException jex) {
                System.out.println(String.format("Error while parsing file %s.", file.getName()));
                System.out.println(jex.getMessage());
            }
        }

        // Generate the content report
        generateReport(listReports, printWriter);

        printWriter.close();
    }

    /**
     * Method to generate the final report.
     *
     * @param listResults List of result of analyze of each file.
     * @param report The text output stream of the report to complete.
     */
    private void generateReport(List<FileReport> listResults, PrintWriter report) throws IOException {
        // Load the file containing the messages to display in the report
        Properties reportProp = new Properties();
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("report.properties");
        reportProp.load(is);

        generateSummaryReport(listResults, report, reportProp);

        generateDetailedReport(listResults, report, reportProp);
    }

    /**
     * Generate the summary part of the report.
     *
     * @param listResults List of result of analyze of each file.
     * @param report The text output stream of the report to complete.
     * @param reportProp Properties file containing the message to display.
     * @throws IOException
     */
    @SuppressWarnings("boxing")
    private void generateSummaryReport(List<FileReport> listResults, PrintWriter report, Properties reportProp)
            throws IOException {

        report.append("Summary\n");
        report.append("#######\n");
        report.append("Number of files analyzed : " + listResults.size() + "\n");

        for (EnumTypeMigration type : EnumTypeMigration.values()) {
            int occurence = 0;
            for (FileReport fileReport : listResults) {
                if (fileReport.getListMigrations().containsKey(type)) {
                    occurence += fileReport.getListMigrations().get(type);
                }
            }

            // If the type of migration is present, it's added to the report
            if (occurence > 0) {
                report.append(" * [" + type.getSeverity() + "] ");
                String key = type.getKeyMessage() + SUFFIX_SUMMARIZED_MESSAGE;
                report.append(MessageFormat.format(reportProp.getProperty(key), occurence));
                report.append('\n');
            }
        }

        report.append("\n");
    }

    /**
     * Generate the summary part of the report.
     *
     * @param listResults List of result of analyze of each file.
     * @param report The text output stream of the report to complete.
     * @param reportProp Properties file containing the message to display.
     * @throws IOException
     */
    private void generateDetailedReport(List<FileReport> listResults, PrintWriter report, Properties reportProp)
            throws IOException {
        report.append("Details\n");
        report.append("#######");
        for (FileReport result : listResults) {
            report.append('\n');
            // Create a section for the file
            report.append(result.getAttachedFile().getName());
            report.append("\n-----------------------\n");

            // If nothing was reported, display a generic message
            if (result.getListMigrations().size() == 0) {
                report.append(reportProp.getProperty(NOTHING_MESSAGE));
                report.append('\n');
            }

            // Get the actions to do for the migration
            for (EnumTypeMigration type : result.getListMigrations().keySet()) {
                List<String> listParams = result.getListParams().get(type);
                String key = type.getKeyMessage() + SUFFIX_DETAILED_MESSAGE;
                if (!reportProp.containsKey(key)) {
                    key = type.getKeyMessage() + SUFFIX_SUMMARIZED_MESSAGE;
                }
                String messageReport = MessageFormat.format(reportProp.getProperty(key), listParams.toArray());
                report.append("[" + type.getSeverity() + "] ");
                report.append(messageReport);
                report.append('\n');
            }
        }
    }

    @Override
    public FileReport analyzeFile(File file, boolean completePath, boolean doMigration, boolean format)
            throws JaxenException, DocumentException {

        FileReport fileReport = new FileReport(file);

        // Check if the file overrides a Nuxeo template
        analyzeOverriddenFile(fileReport, file, completePath, getNuxeoTemplates(), getNuxeoTemplatesCompletePath(),
                EnumTypeMigration.OVERRIDE_RULE);
        analyzeOverriddenFile(fileReport, file, completePath, getNuxeoCompatTemplates(),
                getNuxeoCompatTemplatesCompletePath(), EnumTypeMigration.OVERRIDE_COMPAT_RULE);

        return analyzeFileForRules(file, fileReport, EnumTypeMigration.getTypesMigration(), doMigration, format);
    }

    @Override
    public FileReport analyzeFileForRules(File file, FileReport fileReport, List<EnumTypeMigration> listRules,
            boolean doMigration, boolean format) throws JaxenException, DocumentException {

        SAXReader reader = new SAXReader();

        try {

            reader.setFeature("http://xml.org/sax/features/validation", false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

            Document xhtmlDoc = reader.read(file);
            Document xhtmlOriginal = (Document) xhtmlDoc.clone();

            for (EnumTypeMigration type : listRules) {
                RuleParser parser = type.getInstance(doMigration);
                if (parser != null) {
                    parser.parse(xhtmlDoc, fileReport);
                    if (doMigration) {
                        // If the automatic migration is activated, the parser
                        // tries to do the migration too
                        parser.migrate(xhtmlDoc);
                    }
                }
                // reset the instance of the parser
                type.resetInstance();
            }

            if (doMigration && fileReport.getListMigrations().size() > 0) {
                if (format) {
                    // Format the input file to allow the user to do a diff
                    // easily
                    createFile(xhtmlOriginal, file.getAbsolutePath(), false);
                }
                // Create a new file with the migrations
                createFile(xhtmlDoc, file.getAbsolutePath() + ".migrated", true);
            }
        } catch (DocumentException docEx) {
            // A parsing exception occured, the error is loaded in the
            // FileReport.
            List<String> params = new ArrayList<String>();
            params.add(docEx.getMessage());
            fileReport.getListParams().put(EnumTypeMigration.ERROR_READING_DOCUMENT, params);
            fileReport.getListMigrations().put(EnumTypeMigration.ERROR_READING_DOCUMENT, Integer.valueOf(1));
        } catch (Exception ex) {
            logger.error(String.format("Error while analyzing file '%s' : %s", file.getName(), ex.getMessage()));
        }

        return fileReport;
    }

    /**
     * Create a file containing the migration done in the Document.
     *
     * @param input
     * @param filePath
     * @throws Exception
     */
    protected void createFile(Document input, String filePath, boolean createNewFile) throws Exception {

        // Create file
        File fileMigrated = new File(filePath);
        if (createNewFile) {
            fileMigrated.createNewFile();
        }
        PrintWriter printWriter = new PrintWriter(fileMigrated);
        OutputFormat format = new OutputFormat();
        format.setIndentSize(2);
        format.setNewlines(true);
        format.setTrimText(true);
        XMLWriter writer = new XMLWriter(printWriter, format);
        writer.write(input);

        printWriter.close();
    }

    @Override
    public boolean checkOverriddenTemplate(File file, Set<String> listTemplatesRef, boolean completePath) {
        StringBuilder fileName = new StringBuilder();
        if (completePath) {
            fileName.append("nuxeo.war/");
            List<String> listParents = new ArrayList<>();
            File parent = file.getParentFile();
            if (parent != null && parent.exists()) {
                while (parent != null && !"nuxeo.war".equals(parent.getName())) {
                    listParents.add(parent.getName());
                    parent = parent.getParentFile();
                }
            }
            for (int i = listParents.size() - 1; i >= 0; i--) {
                fileName.append(listParents.get(i));
                fileName.append("/");
            }

        }
        fileName.append(file.getName());

        return listTemplatesRef.contains(fileName.toString());
    }

    public Set<String> getNuxeoTemplates() {
        initListTemplates();
        return nuxeoTemplates;
    }

    public Set<String> getNuxeoTemplatesCompletePath() {
        initListTemplates();
        return nuxeoTemplatesCompletePath;
    }

    public Set<String> getNuxeoCompatTemplates() {
        initListTemplates();
        return nuxeoCompatTemplates;
    }

    public Set<String> getNuxeoCompatTemplatesCompletePath() {
        initListTemplates();
        return nuxeoCompatTemplatesCompletePath;
    }

    /**
     * Init the list of templates in the platform.
     */
    protected void initListTemplates() {
        if (nuxeoTemplates == null) {
            nuxeoTemplates = new HashSet<>();
            nuxeoTemplatesCompletePath = new HashSet<>();
            initTemplates("listTemplatesNuxeoPlatform.txt", nuxeoTemplates, nuxeoTemplatesCompletePath);
        }
        if (nuxeoCompatTemplates == null) {
            nuxeoCompatTemplates = new HashSet<>();
            nuxeoCompatTemplatesCompletePath = new HashSet<>();
            initTemplates("listCompatTemplatesNuxeoPlatform.txt", nuxeoCompatTemplates,
                    nuxeoCompatTemplatesCompletePath);
        }
    }

    protected void initTemplates(String filename, Set<String> templates, Set<String> templatesCompletePath) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(filename);
        if (is == null) {
            logger.error(String.format("File not found at '%s'", filename));
            return;
        }
        InputStreamReader in = new InputStreamReader(is);
        BufferedReader buff = new BufferedReader(in);
        String line = null;
        try {
            while ((line = buff.readLine()) != null) {
                // Add the entire row
                templatesCompletePath.add(line);
                // Add just the name of the file
                String[] splitLine = StringUtils.split(line, '/');
                templates.add(splitLine[splitLine.length - 1]);
            }
        } catch (IOException e) {
            logger.error(String.format("Error while reading file '%s': %s", filename, e.getMessage()), e);
        }
    }

    /**
     * Analyze if a file overrides a Nuxeo template.
     *
     * @param fileReport The FileReport to fill.
     * @param file The file which is been analyzed.
     */
    protected void analyzeOverriddenFile(FileReport fileReport, File file, boolean completePath,
            Set<String> templates, Set<String> templatesCompletePath, EnumTypeMigration rule) {
        // Check if the file is an override of a Nuxeo template
        boolean found = false;
        if (completePath) {
            found = checkOverriddenTemplate(file, templatesCompletePath, completePath);
        } else {
            found = checkOverriddenTemplate(file, templates, completePath);
        }
        if (found) {
            fileReport.getListMigrations().put(rule, Integer.valueOf(1));
            List<String> params = new ArrayList<String>();
            params.add(file.getName());
            fileReport.getListParams().put(rule, params);
        }
    }
}