com.jaspersoft.studio.components.customvisualization.creation.wizard.CustomVisualizationComponentWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.components.customvisualization.creation.wizard.CustomVisualizationComponentWizard.java

Source

/*******************************************************************************
 * Copyright (C) 2010 - 2016. TIBCO Software Inc. 
 * All Rights Reserved. Confidential & Proprietary.
 ******************************************************************************/
package com.jaspersoft.studio.components.customvisualization.creation.wizard;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jaspersoft.studio.JaspersoftStudioPlugin;
import com.jaspersoft.studio.components.customvisualization.CustomVisualizationActivator;
import com.jaspersoft.studio.components.customvisualization.creation.CVCNature;
import com.jaspersoft.studio.components.customvisualization.creation.ModuleDefinition;
import com.jaspersoft.studio.components.customvisualization.creation.ModuleManager;
import com.jaspersoft.studio.components.customvisualization.creation.VelocityLibrary;
import com.jaspersoft.studio.components.customvisualization.creation.VelocityShimLibrary;
import com.jaspersoft.studio.components.customvisualization.messages.Messages;
import com.jaspersoft.studio.components.customvisualization.ui.ComponentDescriptor;
import com.jaspersoft.studio.components.customvisualization.ui.ComponentPropertyDescriptor;
import com.jaspersoft.studio.components.customvisualization.ui.ComponentSectionDescriptor;
import com.jaspersoft.studio.utils.VelocityUtils;
import com.jaspersoft.studio.wizards.JSSWizard;

import net.sf.jasperreports.eclipse.ui.util.UIUtils;
import net.sf.jasperreports.eclipse.util.Misc;
import net.sf.jasperreports.eclipse.wizard.project.ProjectUtil;

/**
 * Wizard to create a custom visualization component project
 * 
 * @author Orlandin Marco
 *
 */
public class CustomVisualizationComponentWizard extends JSSWizard implements INewWizard {

    /**
     * Key to write or read the selected module in the first step from the
     * wizard settings
     */
    protected static final String SELECTED_MODULE_KEY = "selectedModule";

    /**
     * Engine to fill the build.js template
     */
    private VelocityEngine ve = VelocityUtils.getConfiguredVelocityEngine();

    /**
     * Path of the build.js template
     */
    private static final String BUILD_FILE = "com/jaspersoft/studio/components/customvisualization/creation/resources/build.vm"; //$NON-NLS-1$

    /**
     * Page to select the javascript module used by the project
     */
    private CustomVisualizationComponentListPage page0;

    /**
     * Page to get a summary of all the libraries used by the project
     */
    private CustomVisualizationComponentSummaryPage page1;

    /**
     * Page to review the licenses of all the libraries used by the project
     */
    private CustomVisualizationComponentLicensePage page2;

    public CustomVisualizationComponentWizard() {
        super();
        setWindowTitle(Messages.CustomVisualizationComponentWizard_title);
    }

    @Override
    public void init(IWorkbench workbench, IStructuredSelection selection) {
        page0 = new CustomVisualizationComponentListPage();
        addPage(page0);
        page1 = new CustomVisualizationComponentSummaryPage();
        addPage(page1);
        page2 = new CustomVisualizationComponentLicensePage();
        addPage(page2);
    }

    /**
     * Create the project inside the workspace and all it's content
     */
    @Override
    public boolean performFinish() {
        final String projectName = page0.getProjectName();
        final ModuleDefinition selected = page0.getSelectedModule();
        final String mName = page0.getModule();
        final String oldModule = selected.getModuleName();
        try {
            selected.setModuleName(mName);
            getContainer().run(true, true, new IRunnableWithProgress() {

                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    monitor.beginTask("Creating CVC Component Project", IProgressMonitor.UNKNOWN);
                    try {

                        boolean result = createProject(projectName, monitor);
                        if (result) {
                            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
                            IProject project = root.getProject(projectName);
                            File dest = new File(root.getRawLocation().toFile(), projectName);
                            List<VelocityLibrary> libraries = new ArrayList<VelocityLibrary>();
                            List<VelocityShimLibrary> shimLibraries = new ArrayList<VelocityShimLibrary>();

                            try {
                                String outputScriptName = projectName + ".min.js";
                                // Add the main module and all it's
                                // dependencies
                                addModule(selected, shimLibraries, libraries, dest);
                                for (ModuleDefinition requiredLibrary : selected.getRequiredLibraries()) {
                                    addModule(requiredLibrary, shimLibraries, libraries, dest);
                                }

                                String cssFileName = generateCSS(project, monitor, selected);
                                String renderFileName = generateRender(project, monitor, selected);

                                libraries.add(new VelocityLibrary(mName, removeJsExtension(renderFileName)));
                                String buildFile = generateBuildFile(libraries, shimLibraries, mName,
                                        outputScriptName);
                                createFile("build.js", project, buildFile, monitor); //$NON-NLS-1$
                                try {
                                    createUIFiles(monitor, project, mName, cssFileName, selected.getLibraryURL());
                                } catch (IOException e1) {
                                    e1.printStackTrace();
                                }
                                // Eventually create a sample for the
                                // current project
                                createSample(selected, outputScriptName, cssFileName, project, monitor);
                                try {
                                    project.refreshLocal(IProject.DEPTH_INFINITE, monitor);
                                    project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
                                    project.refreshLocal(IProject.DEPTH_INFINITE, monitor);
                                } catch (CoreException e) {
                                    e.printStackTrace();
                                }
                            } catch (FileNotFoundException ex) {
                                MessageDialog.openError(UIUtils.getShell(),
                                        Messages.CustomVisualizationComponentWizard_errorTitle, ex.getMessage());
                            }
                        }
                    } finally {
                        monitor.done();
                        selected.setModuleName(oldModule);
                    }
                }
            });
        } catch (InvocationTargetException e) {
            UIUtils.showError(e.getCause());
        } catch (InterruptedException e) {
            UIUtils.showError(e);
        }
        return true;
    }

    protected void createUIFiles(IProgressMonitor monitor, IProject project, String mName, String cssFName,
            String jsFName) throws IOException {
        if (page0.isCreateUI()) {

            String uiIconPath = page0.getUiIconPath();
            String thName = null;
            if (Misc.isNullOrEmpty(uiIconPath)) {
                URL img = CustomVisualizationActivator.getDefault().getBundle().getResource("icons/blank_a4.png");
                thName = FilenameUtils.getName(img.toString());
                createFile(thName, project, img.openStream(), monitor);
            } else {
                File f = new File(uiIconPath);
                thName = f.getName();
                createFile(thName, project, f.toURI().toURL().openStream(), monitor);
            }
            ComponentDescriptor cd = new ComponentDescriptor();
            cd.setLabel(page0.getUiLabel());
            cd.setDescription(page0.getUiDescription());
            cd.setThumbnail(thName);
            cd.setModule(mName);

            List<ComponentSectionDescriptor> sections = new ArrayList<ComponentSectionDescriptor>();
            ComponentSectionDescriptor csd = new ComponentSectionDescriptor();
            csd.setExpandable(false);
            csd.setName("Script");

            List<ComponentPropertyDescriptor> props = new ArrayList<ComponentPropertyDescriptor>();
            ComponentPropertyDescriptor cpd = new ComponentPropertyDescriptor();
            cpd.setType("TEXT");
            cpd.setName("module");
            cpd.setLabel("Module");
            cpd.setDescription("Module name");
            cpd.setDefaultValue(mName);
            cpd.setReadOnly(true);
            cpd.setMandatory(true);
            props.add(cpd);

            if (cssFName != null) {
                cpd = new ComponentPropertyDescriptor();
                cpd.setType("PATH");
                cpd.setName("css");
                cpd.setLabel("CSS Path");
                cpd.setDescription("CSS Path");
                cpd.setDefaultValue(cssFName);
                cpd.setReadOnly(false);
                cpd.setMandatory(true);
                props.add(cpd);
            }

            cpd = new ComponentPropertyDescriptor();
            cpd.setType("PATH");
            cpd.setName("script");
            cpd.setLabel("Script Path");
            cpd.setDescription("Script path");
            cpd.setDefaultValue(new File(jsFName).getName());
            cpd.setReadOnly(false);
            cpd.setMandatory(true);
            props.add(cpd);

            csd.setProperties(props);

            sections.add(csd);

            cd.setSections(sections);

            ObjectMapper mapper = new ObjectMapper();
            mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
            createFile(mName + ".json", project, mapper.writerWithDefaultPrettyPrinter().writeValueAsString(cd), //$NON-NLS-1$
                    monitor);
        }
    }

    /**
     * Check if the selected module provide some samples, like a sample jrxml or
     * its resources. In this case it add the jr nature to the project and copy
     * all the specified resources inside the project
     * 
     * @param selectedModule
     *            the selected module
     * @param scriptName
     *            the name of the output script that will be generated when the
     *            project component is compiled
     * @param cssName
     *            name of the css file if any, could be null if no css is
     *            provided
     * @param project
     *            the current project
     * @param monitor
     *            monitor to execute the operation
     */
    private void createSample(ModuleDefinition selectedModule, String scriptName, String cssName, IProject project,
            IProgressMonitor monitor) {
        if (!selectedModule.getSampleResources().isEmpty()) {
            try {
                // It uses the samples, add the jr nature to the project
                if (!ProjectUtil.hasJRNature(monitor, project)) {
                    ProjectUtil.createJRProject(monitor, project);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            for (String resourcePath : selectedModule.getSampleResources()) {
                InputStream resource = selectedModule.getResource(resourcePath);
                if (resource != null) {
                    String resourceName = getResourceName(resourcePath);
                    if (resourceName.toLowerCase().endsWith(".jrxml")) {
                        // It's a jrxml, call the generate method to provide
                        // some project dependent informations
                        String jrxmlContent = generateJRXML(resourcePath, scriptName, cssName,
                                selectedModule.getModuleName());
                        createFile(selectedModule.getModuleName() + "_sample.jrxml", project, jrxmlContent,
                                monitor);
                    } else {
                        // It's another resource file (maybe required from the
                        // jrxml), simply create it in the folder
                        createFile(resourceName, project, resource, monitor);
                    }
                }
            }
        }
    }

    /**
     * Generate a sample jrxml for the project by starting from an existing
     * jrxml and doing some substitution. Actually only the script name is write
     * inside the final sample jrxml
     * 
     * @param jrxmlPath
     *            path to the sample template
     * @param scriptName
     *            name of the script to use along with the template to generate
     *            the sample jrxml
     * @param cssName
     *            name of the css file if any, could be null if no css is
     *            provided
     * @return the content of the sample jrxml
     */
    private String generateJRXML(String jrxmlPath, String scriptName, String cssName, String moduleName) {
        VelocityContext functionContext = new VelocityContext();
        functionContext.put("scriptname", scriptName); //$NON-NLS-1$
        functionContext.put("cssname", cssName); //$NON-NLS-1$
        functionContext.put("modulename", moduleName); //$NON-NLS-1$

        Template functionTemplate = ve.getTemplate(jrxmlPath);
        StringWriter fsw = new StringWriter();
        functionTemplate.merge(functionContext, fsw);
        return fsw.toString();
    }

    /**
     * Return a resource name starting from it's path. To find the resource name
     * the last / is searched, if not found it will return the path itself,
     * otherwise the substring after the last /
     * 
     * @param resourcePath
     *            a path of a resource
     * @return a not null string
     */
    private String getResourceName(String resourcePath) {
        int slash = resourcePath.lastIndexOf("/");
        if (slash == -1)
            return resourcePath;
        else
            return resourcePath.substring(slash + 1);
    }

    /**
     * Get a resource name and if it ends with the js extension then the
     * extension is removed
     * 
     * @param source
     *            the name of the resource
     * @return the name without the extension if it was a .js, otherwise the
     *         source
     */
    private String removeJsExtension(String source) {
        if (source.toLowerCase().endsWith(".js"))
            return source.substring(0, source.length() - 3);
        return source;
    }

    /**
     * Add a module to the project, it's library is added on the project folder
     * and are created the informations to have it added to the build.js file
     * 
     * @param module
     *            the module to add
     * @param shimmedList
     *            the list of library to added to the shim list
     * @param librariesList
     *            the list of library to add to the path list
     * @param projectFolder
     *            the project folder
     * @throws FileNotFoundException
     *             throw the exception if the library file can not be found
     */
    private void addModule(ModuleDefinition module, List<VelocityShimLibrary> shimmedList,
            List<VelocityLibrary> librariesList, File projectFolder) throws FileNotFoundException {
        // Check if the name is null because a module could not have a library
        String fileName = module.getLibraryFilename();
        if (fileName != null) {
            File resourceFile = ModuleManager.getLibraryFile(module);
            if (resourceFile != null && resourceFile.exists()) {
                File workspaceCopy = new File(projectFolder, fileName);
                try {
                    FileUtils.copyFile(resourceFile, workspaceCopy);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // ADD THE LIBRARY TO THE LIBRARIES LIST
                librariesList.add(new VelocityLibrary(module.getVariableName(), removeJsExtension(fileName)));
                // CHECK IF THE MODULE MUST BE SHIMMED
                if (module.isNeedShim()) {
                    String dependencies = ""; //$NON-NLS-1$
                    for (int i = 0; i < module.getShimDependencies().size(); i++) {
                        dependencies += "'" + module.getShimDependencies().get(i) + "'"; //$NON-NLS-1$ //$NON-NLS-2$
                        if (i < (module.getShimDependencies().size() - 1)) {
                            dependencies += ","; //$NON-NLS-1$
                        }
                    }
                    VelocityShimLibrary shimLibrary = new VelocityShimLibrary(module.getVariableName(),
                            module.getShimExportName(), dependencies);
                    shimmedList.add(shimLibrary);
                }

            } else {
                String errorMessage = MessageFormat.format(
                        Messages.CustomVisualizationComponentWizard_errorDescription,
                        new Object[] { module.getLibraryURL() });
                throw new FileNotFoundException(errorMessage);
            }
        }
    }

    /**
     * Generate for the new custom visualization component project the css file
     * 
     * @param container
     *            the container where the fill will be placed
     * @param monitor
     *            the monitor to execute the operation
     * @param library
     *            the module selected by the user in the wizard page
     * @return the name of the css file or null if no css is provided by the
     *         module
     */
    private String generateCSS(IProject container, IProgressMonitor monitor, ModuleDefinition module) {
        String cssContent = module.getCssResource();
        if (cssContent != null) {
            String cssName = container.getName() + ".css";
            createFile(cssName, container, cssContent, monitor); // $NON-NLS-1$
            return cssName;
        }
        return null;
    }

    /**
     * Generate for the new custom visualization component project the render
     * file
     * 
     * @param container
     *            the container where the fill will be placed
     * @param monitor
     *            the monitor to execute the operation
     * @param library
     *            the module selected by the user in the wizard page
     */
    private String generateRender(IProject container, IProgressMonitor monitor, ModuleDefinition library) {
        String renderContent = library.getRenderResource();
        if (renderContent != null) {
            String renderFileName = container.getName() + ".js";
            createFile(renderFileName, container, generateJsResource(renderContent, library.getModuleName()),
                    monitor); // $NON-NLS-1$
            return renderFileName;
        }
        return null;
    }

    private String generateJsResource(String content, String moduleName) {
        VelocityContext functionContext = new VelocityContext();
        functionContext.put("modulename", moduleName); //$NON-NLS-1$

        // Template functionTemplate = ve.getTemplate(jrxmlPath);
        StringWriter fsw = new StringWriter();
        Velocity.evaluate(functionContext, fsw, "", content);

        // functionTemplate.merge(functionContext, fsw);
        return fsw.toString();
    }

    /**
     * Generate the build.js file using the template mixed with the data
     * provided during the wizard
     * 
     * @param libraries
     *            the list of javascript libraries to include inside the build
     *            file
     * @param shimLibraries
     *            the list of javascript shimmed libraries to include inside the
     *            build file
     * @param modulename
     *            the name of the folder where the project is contained, that it
     *            is used as module name
     */
    private String generateBuildFile(List<VelocityLibrary> libraries, List<VelocityShimLibrary> shimLibraries,
            String moduleName, String outputName) {
        VelocityContext functionContext = new VelocityContext();
        functionContext.put("libraries", libraries); //$NON-NLS-1$
        functionContext.put("hasShim", shimLibraries.size() > 0); //$NON-NLS-1$
        functionContext.put("shimlibraries", shimLibraries); //$NON-NLS-1$
        functionContext.put("modulename", moduleName); //$NON-NLS-1$
        functionContext.put("outputname", outputName); //$NON-NLS-1$

        Template functionTemplate = ve.getTemplate(BUILD_FILE);
        StringWriter fsw = new StringWriter();
        functionTemplate.merge(functionContext, fsw);
        return fsw.toString();
    }

    /**
     * Add a textual file to the project
     * 
     * @param name
     *            the name of the file
     * @param container
     *            the container of the file
     * @param content
     *            the textual content of the file
     * @param progressMonitor
     *            a progress monitor
     * @return the added file
     */
    protected static IFile createFile(String name, IContainer container, String content,
            IProgressMonitor progressMonitor) {
        try {
            final InputStream stream = new ByteArrayInputStream(
                    content.getBytes(container.getDefaultCharset(true)));
            return createFile(name, container, stream, progressMonitor);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * Add a file to the project
     * 
     * @param name
     *            the name of the file
     * @param container
     *            the container of the file
     * @param stream
     *            the binary content of the file
     * @param progressMonitor
     *            a progress monitor
     * @return the added file
     */
    protected static IFile createFile(String name, IContainer container, InputStream stream,
            IProgressMonitor progressMonitor) {
        final IFile file = container.getFile(new Path(name));
        try {
            if (file.exists()) {
                file.setContents(stream, true, true, progressMonitor);
            } else {
                file.create(stream, true, progressMonitor);
            }
            stream.close();
        } catch (final Exception e) {
            JaspersoftStudioPlugin.getInstance().logError(e);
        }
        progressMonitor.worked(1);

        return file;
    }

    /**
     * Create an empty project inside the workspace with the nature of a custom
     * visualization component
     * 
     * @param projectName
     *            the name of the project
     * @param monitor
     *            monitor to execute the operation
     * @return true if the project was created correctly, false otherwise
     */
    private boolean createProject(String projectName, IProgressMonitor monitor) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        try {
            if (!project.exists()) {
                project.create(monitor);
                project.open(monitor);

                ProjectUtil.addNature(project, CVCNature.NATURE_ID, monitor);

                // IFolder folder =
                // project.getFolder(PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_BINNAME));
                // folder.create(IResource.FORCE | IResource.DERIVED, true,
                // monitor);
                // folder.setDerived(true, monitor);

                project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
                IProjectDescription description = project.getDescription();
                description.setName(Messages.CustomVisualizationComponentWizard_projectDescription);
                project.setDescription(description, monitor);
                return true;
            }
        } catch (CoreException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Can finish if all the pages are complete or if only the first page is
     * available and it is complete
     */
    @Override
    public boolean canFinish() {
        if (!page0.hasLibraryPage())
            return page0.isPageComplete();
        else
            return super.canFinish();
    }
}