blob: 5f36791fe10f6a86211278864e2ad3aa756bb69f [file] [log] [blame]
/*************************************************************************************
* Copyright (c) 2011-2018 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
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.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.window.Window;
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.handlers.HandlerUtil;
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.ProfileData;
import org.eclipse.m2e.profiles.core.internal.ProfileState;
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;
/**
* 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(() -> {
List<ProfileSelection> sharedProfiles = getProfilesJob.getSharedProfiles();
Map<IMavenProjectFacade, List<ProfileData>> allProfiles = getProfilesJob.getAllProfiles();
final SelectProfilesDialog dialog = new SelectProfilesDialog(shell, facades, sharedProfiles);
if(dialog.open() == Window.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>();
if(currentSelection != null) {
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;
}
}
}