/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.eclipse.dsl.classpath; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.codehaus.groovy.eclipse.core.model.GroovyRuntime; import org.codehaus.groovy.eclipse.dsl.DSLPreferences; import org.codehaus.groovy.eclipse.dsl.DSLPreferencesInitializer; import org.codehaus.groovy.eclipse.dsl.GroovyDSLCoreActivator; import org.codehaus.jdt.groovy.model.GroovyNature; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceRuleFactory; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.MultiRule; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jface.preference.IPersistentPreferenceStore; import org.eclipse.jface.preference.IPreferenceStore; /** * This class is called on startup as well as whenever there is a project added to the workspace. * If the option is set, then the DSL support will be secretly added to all groovy projects * @author andrew * @created May 27, 2011 */ public class AutoAddContainerSupport implements IResourceChangeListener { private final class AddDSLSupportJob extends Job { private final String projectName; private final IJavaProject project; private AddDSLSupportJob(String name, String projectName, IJavaProject project) { super(name); this.projectName = projectName; this.project = project; } @Override public IStatus run(IProgressMonitor monitor) { try { GroovyRuntime.addLibraryToClasspath(project, GroovyDSLCoreActivator.CLASSPATH_CONTAINER_ID, false); // here, remember that we have added this project alreadyAddedProjects.add(projectName); return Status.OK_STATUS; } catch (JavaModelException e) { GroovyDSLCoreActivator.logException("Problem auto-adding DSL support to " + projectName, e); return e.getStatus(); } } } private final IPreferenceStore store = GroovyDSLCoreActivator.getDefault().getPreferenceStore(); private final Set<String> alreadyAddedProjects; public AutoAddContainerSupport() { alreadyAddedProjects = new HashSet<String>(); String toIgnore = store.getString(DSLPreferencesInitializer.PROJECTS_TO_IGNORE); if (toIgnore != null) { String[] split = toIgnore.split(","); for (String projName : split) { projName = projName.trim(); if (projName.length() > 0 && ResourcesPlugin.getWorkspace().getRoot().getProject(projName).exists()) { alreadyAddedProjects.add(projName); } } } } private boolean shouldAddSupport() { return store.getBoolean(DSLPreferences.AUTO_ADD_DSL_SUPPORT) || store.getBoolean(DSLPreferences.DISABLED_SCRIPTS); } // will add container if it doesn't already exist private void addContainer(final IJavaProject project) { final String projectName = project.getElementName(); AddDSLSupportJob runnable = new AddDSLSupportJob("Add DSL Support", projectName, project); runnable.setPriority(Job.BUILD); runnable.setSystem(true); //Next line is very important! Otherwise => race condition with GrailsProjectVersionFixer! runnable.setRule(getSetClassPathSchedulingRule(project)); runnable.schedule(); } /** * Same scheduling rule as {@link SetClasspathOperation} */ private ISchedulingRule getSetClassPathSchedulingRule(IJavaProject project) { //copied from SetClassPathOperation. Rules must match (or be wider than this rule or the setClassPathOperation will fail) IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace().getRuleFactory(); return new MultiRule(new ISchedulingRule[] { // use project modification rule as this is needed to create the .classpath file if it doesn't exist yet, or to update project references ruleFactory.modifyRule(project.getProject()), // and external project modification rule in case the external folders are modified ruleFactory.modifyRule(JavaModelManager.getExternalManager().getExternalFoldersProject()), }); } public void addContainerToAll() { if (!shouldAddSupport()) { return; } IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : allProjects) { if (!alreadyAddedProjects.contains(project.getName()) && GroovyNature.hasGroovyNature(project)) { addContainer(JavaCore.create(project)); } } } public void resourceChanged(IResourceChangeEvent event) { if (!shouldAddSupport()) { return; } // look for projects that are becoming groovy projects, or projects that are being created // we can approximate this by looking for changes in .project files IResourceDelta delta = event.getDelta(); if (delta != null) { List<IProject> projects = new ArrayList<IProject>(); if (delta.getAffectedChildren().length > 0) { IResourceDelta[] children = delta.getAffectedChildren(); for (IResourceDelta child : children) { if (child.getResource() instanceof IProject) { if (child.getAffectedChildren().length == 0) { projects.add((IProject) child.getResource()); } else { for (IResourceDelta childDelta : child.getAffectedChildren()) { IResource r = childDelta.getResource(); if (r instanceof IFile && r.getName().equals(".project")) { projects.add((IProject) child.getResource()); } } } } } } for (IProject project : projects) { if (!alreadyAddedProjects.contains(project.getName()) && GroovyNature.hasGroovyNature(project)) { addContainer(JavaCore.create(project)); } } } } public void dispose() { StringBuilder sb = new StringBuilder(); for (String projName : alreadyAddedProjects) { sb.append(projName); sb.append(","); } if (sb.length() > 0) { sb.replace(sb.length()-1, sb.length(), ""); } store.setValue(DSLPreferencesInitializer.PROJECTS_TO_IGNORE, sb.toString()); if (store instanceof IPersistentPreferenceStore) { try { ((IPersistentPreferenceStore) store).save(); } catch (IOException e) { GroovyDSLCoreActivator.logException(e); } } } public void ignoreProject(IProject project) { alreadyAddedProjects.add(project.getName()); } public void unignoreProject(IProject project) { alreadyAddedProjects.remove(project.getName()); } public void unignoreAllProjects() { alreadyAddedProjects.clear(); } }