/************************************************************************************* * Copyright (c) 2011-2014 Red Hat, Inc. and others. * 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Fred Bricon / JBoss by Red Hat - Initial implementation. ************************************************************************************/ package org.eclipse.m2e.profiles.ui.internal.actions; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.ui.internal.actions.SelectionUtil; import org.eclipse.m2e.profiles.core.internal.IProfileManager; import org.eclipse.m2e.profiles.core.internal.MavenProfilesCoreActivator; import org.eclipse.m2e.profiles.core.internal.ProfileState; import org.eclipse.m2e.profiles.core.internal.ProfileData; import org.eclipse.m2e.profiles.ui.internal.MavenProfilesUIActivator; import org.eclipse.m2e.profiles.ui.internal.Messages; import org.eclipse.m2e.profiles.ui.internal.dialog.ProfileSelection; import org.eclipse.m2e.profiles.ui.internal.dialog.SelectProfilesDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.handlers.HandlerUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Handles profile selection commands. * * @author Fred Bricon * @since 1.5 */ public class ProfileSelectionHandler extends AbstractHandler { private static final Logger log = LoggerFactory.getLogger(ProfileSelectionHandler.class); /** * Opens the Maven profile selection Dialog window. */ public Object execute(ExecutionEvent event) throws ExecutionException { IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event); IProject[] projects = getSelectedProjects(event); return execute(window.getShell(), projects); } private IProject[] getSelectedProjects(ExecutionEvent event) { ISelection selection = HandlerUtil.getCurrentSelection(event); IProject[] projects = SelectionUtil.getProjects(selection, false); if (projects.length == 0) { IEditorInput input = HandlerUtil.getActiveEditorInput(event); if (input instanceof IFileEditorInput) { IFileEditorInput fileInput = (IFileEditorInput) input; projects = new IProject[] { fileInput.getFile().getProject() }; } } return projects; } public IStatus execute(Shell shell, IProject... projects) throws ExecutionException { Set<IMavenProjectFacade> facades = getMavenProjects(projects); if (facades.isEmpty()) { display(shell, Messages.ProfileSelectionHandler_Select_some_maven_projects); return null; } final IProfileManager profileManager = MavenProfilesCoreActivator.getDefault().getProfileManager(); GetProfilesJob getProfilesJob = new GetProfilesJob(facades, profileManager); getProfilesJob.addJobChangeListener(onProfilesFetched(getProfilesJob, facades, profileManager, shell)); getProfilesJob.setUser(true); getProfilesJob.schedule(); return Status.OK_STATUS; } private IJobChangeListener onProfilesFetched(final GetProfilesJob getProfilesJob, final Set<IMavenProjectFacade> facades, final IProfileManager profileManager, final Shell shell) { return new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { if (getProfilesJob.getResult().isOK()) { shell.getDisplay().syncExec(new Runnable() { public void run() { List<ProfileSelection> sharedProfiles = getProfilesJob.getSharedProfiles(); Map<IMavenProjectFacade, List<ProfileData>> allProfiles = getProfilesJob.getAllProfiles(); final SelectProfilesDialog dialog = new SelectProfilesDialog(shell, facades, sharedProfiles); if(dialog.open() == Dialog.OK) { Job job = new UpdateProfilesJob(allProfiles, sharedProfiles, profileManager, dialog); job.setRule( MavenPlugin.getProjectConfigurationManager().getRule()); job.schedule(); } } }); } } }; } private void display(Shell shell, String message) { MessageDialog.openInformation( shell, Messages.SelectProfilesDialog_Select_Maven_profiles, message); } /** * Returns an IMavenProjectFacade from the selected IResource, or from the * active editor * * @param event * @return the selected IMavenProjectFacade */ private Set<IMavenProjectFacade> getMavenProjects(IProject[] projects) { if (projects == null || projects.length == 0) { return Collections.emptySet(); } Set<IMavenProjectFacade> facades = new HashSet<IMavenProjectFacade>(projects.length); try { IProgressMonitor monitor = new NullProgressMonitor(); for (IProject p : projects) { if (p != null && p.isAccessible() && p.hasNature(IMavenConstants.NATURE_ID)) { IFile pom = p.getFile(IMavenConstants.POM_FILE_NAME); IMavenProjectFacade facade = MavenPlugin.getMavenProjectRegistry().create(pom, true, monitor); facades.add(facade); } } } catch (CoreException e) { log.error("Unable to select Maven projects", e); } return facades; } class GetProfilesJob extends Job { private IProfileManager profileManager; private Set<IMavenProjectFacade> facades; private Map<IMavenProjectFacade, List<ProfileData>> allProfiles; private List<ProfileSelection> sharedProfiles; private GetProfilesJob(final Set<IMavenProjectFacade> facades, IProfileManager profileManager) { super(Messages.ProfileSelectionHandler_Loading_maven_profiles); this.facades = facades; this.profileManager = profileManager; } @Override protected IStatus run(IProgressMonitor monitor) { try { this.allProfiles = getAllProfiles(facades, profileManager); this.sharedProfiles = getSharedProfiles(allProfiles); } catch (CoreException e) { return new Status(IStatus.ERROR, MavenProfilesUIActivator.PLUGIN_ID, Messages.ProfileSelectionHandler_Unable_to_open_profile_dialog, e); } return Status.OK_STATUS; } private List<ProfileSelection> getSharedProfiles( Map<IMavenProjectFacade, List<ProfileData>> projectProfilesMap) { List<ProfileData> currentSelection = null; List<List<ProfileData>> projectProfiles = new ArrayList<List<ProfileData>>(projectProfilesMap.values()); int smallestSize = Integer.MAX_VALUE; for (List<ProfileData> profiles : projectProfiles) { int size = profiles.size(); if (size < smallestSize) { smallestSize = size; currentSelection = profiles; } } projectProfiles.remove(currentSelection); // Init the smallest profiles selection possible List<ProfileSelection> selection = new ArrayList<ProfileSelection>(); for (ProfileData p : currentSelection) { ProfileSelection ps = new ProfileSelection(); ps.setId(p.getId()); ps.setActivationState(p.getActivationState()); ps.setAutoActive(p.isAutoActive()); ps.setSource(p.getSource()); ps.setSelected(p.isUserSelected()); selection.add(ps); } if (!projectProfiles.isEmpty()) { // Restrict to the common profiles only Iterator<ProfileSelection> ite = selection.iterator(); while (ite.hasNext()) { ProfileSelection p = ite.next(); for (List<ProfileData> statuses : projectProfiles) { ProfileData s = hasProfile(p.getId(), statuses); if (s == null) { // remove any non-common profile selection ite.remove(); break; } // reset non common settings if (p.getAutoActive() != null && !p.getAutoActive().equals(s.isAutoActive())) { p.setAutoActive(null); } if (p.getSource() != null && !p.getSource().equals(s.getSource())) { p.setSource(Messages.ProfileSelectionHandler_multiple_definitions); } if (p.getSelected() != null && !p.getSelected().equals(s.isUserSelected())) { p.setSelected(null); } if (p.getActivationState() != null && !p.getActivationState().equals(s.getActivationState())) { p.setActivationState(null); p.setAutoActive(null); } } } } return selection; } private ProfileData hasProfile(String id, List<ProfileData> statuses) { for (ProfileData p : statuses) { if (id.equals(p.getId())) { return p; } } return null; } private Map<IMavenProjectFacade, List<ProfileData>> getAllProfiles(final Set<IMavenProjectFacade> facades, final IProfileManager profileManager) throws CoreException { Map<IMavenProjectFacade, List<ProfileData>> allProfiles = new HashMap<IMavenProjectFacade, List<ProfileData>>(facades.size()); IProgressMonitor monitor = new NullProgressMonitor(); for (IMavenProjectFacade facade : facades) { allProfiles.put(facade, profileManager.getProfileDatas(facade, monitor)); } return allProfiles; } public List<ProfileSelection> getSharedProfiles() { return sharedProfiles; } public Map<IMavenProjectFacade, List<ProfileData>> getAllProfiles() { return allProfiles; } } class UpdateProfilesJob extends WorkspaceJob { private Map<IMavenProjectFacade, List<ProfileData>> allProfiles; private List<ProfileSelection> sharedProfiles; private IProfileManager profileManager; private SelectProfilesDialog dialog; private UpdateProfilesJob(Map<IMavenProjectFacade, List<ProfileData>> allProfiles, List<ProfileSelection> sharedProfiles, IProfileManager profileManager, SelectProfilesDialog dialog) { super(Messages.ProfileManager_Updating_maven_profiles); this.allProfiles = allProfiles; this.sharedProfiles = sharedProfiles; this.profileManager = profileManager; this.dialog = dialog; } public IStatus runInWorkspace(IProgressMonitor monitor) { try { SubMonitor progress = SubMonitor.convert(monitor, Messages.ProfileManager_Updating_maven_profiles, 100); SubMonitor subProgress = SubMonitor.convert(progress.newChild(5), allProfiles.size() * 100); for (Map.Entry<IMavenProjectFacade, List<ProfileData>> entry : allProfiles.entrySet()) { if (progress.isCanceled()) { throw new OperationCanceledException(); } IMavenProjectFacade facade = entry.getKey(); List<String> activeProfiles = getActiveProfiles(sharedProfiles, entry.getValue()); profileManager.updateActiveProfiles(facade, activeProfiles, dialog.isOffline(), dialog.isForceUpdate(), subProgress.newChild(100)); } } catch (CoreException ex) { log.error("Unable to update Maven profiles", ex); return ex.getStatus(); } return Status.OK_STATUS; } private List<String> getActiveProfiles( List<ProfileSelection> sharedProfiles, List<ProfileData> availableProfiles) { List<String> ids = new ArrayList<String>(); for (ProfileData st : availableProfiles) { ProfileSelection selection = findSelectedProfile(st.getId(), sharedProfiles); String id = null; boolean isDisabled = false; if (selection == null) { // was not displayed. Use existing value. if (st.isUserSelected()) { id = st.getId(); isDisabled = st.getActivationState().equals(ProfileState.Disabled); } } else { if (null == selection.getSelected()) { // Value was displayed but its state is unknown, use // previous state if (st.isUserSelected()) { id = st.getId(); isDisabled = st.getActivationState().equals(ProfileState.Disabled); } } else { // Value was displayed and is consistent if (Boolean.TRUE.equals(selection.getSelected())) { id = selection.getId(); isDisabled = selection.getActivationState().equals(ProfileState.Disabled); } } } if (id != null) { if (isDisabled) { id = "!" + id; //$NON-NLS-1$ } ids.add(id); } } return ids; } private ProfileSelection findSelectedProfile(String id, List<ProfileSelection> sharedProfiles) { for (ProfileSelection sel : sharedProfiles) { if (id.equals(sel.getId())) { return sel; } } return null; } } }