org.grails.ide.eclipse.ui.internal.importfixes.GrailsOutputFolderFixer.java Source code

Java tutorial

Introduction

Here is the source code for org.grails.ide.eclipse.ui.internal.importfixes.GrailsOutputFolderFixer.java

Source

/*******************************************************************************
 * Copyright (c) 2012 VMWare, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     VMWare, Inc. - initial API and implementation
 *******************************************************************************/
package org.grails.ide.eclipse.ui.internal.importfixes;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.grails.ide.eclipse.commands.GrailsCommandUtils;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.internal.GrailsNature;

/**
 * An instance of this class is responsible for fixing the output folder of a Grails project
 * if it overlaps with the output folder used by grails war command.
 * <p>
 * This functionality is hooked and triggered in two ways:
 *   - called from GrailsProjectVersionFixer
 *   - makes a scan of existing grails projects in the workspace when it starts.
 *  
 * @author Kris De Volder
 *
 * @since 2.8
 */
public class GrailsOutputFolderFixer {

    /**
     * The project relative path that is used by the grails war command as its output folder.
     */
    private static final IPath GRAILS_WAR_OUTPUT_FOLDER = new Path("web-app/WEB-INF/classes");

    public GrailsOutputFolderFixer(GrailsProjectVersionFixer versionFixer) {
        versionFixer.setGrailsOutputFolderFixer(this); //Allows version fixer to call us when new grails projects are detected.
        scanExistingGrailsProjects();
    }

    /**
     * This method is public *only* for testing purposes. It shouldn't be called directly from
     * outside this class.
     */
    public void scanExistingGrailsProjects() {
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        for (IProject p : projects) {
            if (GrailsNature.looksLikeGrailsProject(p)) {
                fix(p);
            }
        }
    }

    public void dispose() {
    }

    /**
     * Called by project version fixer when it detects a new grails project in the workspace.
     * <p>
     * This is called after the version fixer has already applied its fixer logic. (But beware that
     * the fixer actually shedules most of its work as jobs so the actually fixes probably
     * have not yet been applied.
     */
    public void fix(IProject project) {
        try {
            if (project.hasNature(JavaCore.NATURE_ID)) {
                final IJavaProject javaProject = JavaCore.create(project);
                IPath outputFolder = javaProject.getOutputLocation();
                if (isBadOutputFolder(outputFolder)) {
                    WorkspaceJob job = new WorkspaceJob("Fix output folder") {
                        @Override
                        public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
                            try {
                                //We recheck the fixing condition because, it may have changed by the time the job is scheduled.
                                //This is because version fixer in some cases calls eclipsify (also from a scheduled job) and
                                //this also fixes the output folder. It is probably harmless to fix twice, but it does
                                //cause a potential build, so it is best not to do it.
                                IPath outputFolder = javaProject.getOutputLocation();
                                if (isBadOutputFolder(outputFolder)) {
                                    GrailsCommandUtils.setDefaultOutputFolder(javaProject);
                                }
                                return Status.OK_STATUS;
                            } catch (Exception e) {
                                return new Status(IStatus.WARNING, GrailsCoreActivator.PLUGIN_ID,
                                        "Error while fixing output folder for project "
                                                + javaProject.getElementName());
                            }
                        }
                    };
                    job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
                    job.setPriority(Job.INTERACTIVE);
                    job.schedule();
                }
            }
        } catch (Exception e) {
            GrailsCoreActivator.log(e);
        }
    }

    private boolean isBadOutputFolder(IPath outputFolder) {
        return outputFolder.removeFirstSegments(1).equals(GRAILS_WAR_OUTPUT_FOLDER);
    }

}