blob: 99cfefdae25ebc6c3a05e3f8f992f111dc44b9e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2014 Sonatype, 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:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.core.ui.internal.wizards;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.apache.maven.archetype.catalog.Archetype;
import org.apache.maven.archetype.catalog.ArchetypeCatalog;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.archetype.ArchetypeUtil;
import org.eclipse.m2e.core.embedder.ArtifactKey;
import org.eclipse.m2e.core.embedder.IMaven;
import org.eclipse.m2e.core.internal.MavenPluginActivator;
import org.eclipse.m2e.core.internal.archetype.ArchetypeCatalogFactory;
import org.eclipse.m2e.core.internal.archetype.ArchetypeManager;
import org.eclipse.m2e.core.internal.index.IMutableIndex;
import org.eclipse.m2e.core.internal.index.IndexListener;
import org.eclipse.m2e.core.internal.index.IndexManager;
import org.eclipse.m2e.core.project.ProjectImportConfiguration;
import org.eclipse.m2e.core.repository.IRepository;
import org.eclipse.m2e.core.ui.internal.M2EUIPluginActivator;
import org.eclipse.m2e.core.ui.internal.Messages;
import org.eclipse.m2e.core.ui.internal.util.M2EUIUtils;
/**
* Maven Archetype selection wizard page presents the user with a list of available Maven Archetypes available for
* creating new project.
*/
public class MavenProjectWizardArchetypePage extends AbstractMavenWizardPage implements IndexListener {
private static final Logger log = LoggerFactory.getLogger(MavenProjectWizardArchetypePage.class);
private static final String KEY_CATALOG = "catalog"; //$NON-NLS-1$
private static final String ALL_CATALOGS = org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_all;
public static final Comparator<Archetype> ARCHETYPE_COMPARATOR = (a1, a2) -> {
String g1 = a1.getGroupId();
String g2 = a2.getGroupId();
int res = g1.compareTo(g2);
if(res != 0) {
return res;
}
String i1 = a1.getArtifactId();
String i2 = a2.getArtifactId();
res = i1.compareTo(i2);
if(res != 0) {
return res;
}
String v1 = a1.getVersion();
String v2 = a2.getVersion();
if(v1 == null) {
return v2 == null ? 0 : -1;
}
return v1.compareTo(v2);
};
private static final boolean DEFAULT_SHOW_LAST_VERSION = true;
private static final boolean DEFAULT_INCLUDE_SNAPSHOTS = false;
private Map<String, List<Archetype>> archetypesCache = new HashMap<>();
ComboViewer catalogsComboViewer;
Text filterText;
/** the archetype table viewer */
TableViewer viewer;
/** the description value label */
Text descriptionText;
Button showLastVersionButton;
Button includeShapshotsButton;
Button addArchetypeButton;
/** the list of available archetypes */
volatile Collection<Archetype> archetypes;
/**
* Archetype key to known archetype versions map. Versions are sorted in newest-to-oldest order.
*/
Map<String, List<ArtifactVersion>> archetypeVersions;
/** a flag indicating if the archetype selection is actually used in the wizard */
private boolean isUsed = true;
ArchetypeCatalogFactory catalogFactory = null;
private RetrievingArchetypesJob job;
/**
* Default constructor. Sets the title and description of this wizard page and marks it as not being complete as user
* input is required for continuing.
*/
public MavenProjectWizardArchetypePage(ProjectImportConfiguration projectImportConfiguration) {
super("MavenProjectWizardArchetypePage", projectImportConfiguration); //$NON-NLS-1$
setTitle(Messages.wizardProjectPageArchetypeTitle);
setDescription(Messages.wizardProjectPageArchetypeDescription);
setPageComplete(false);
}
/** Creates the page controls. */
public void createControl(Composite parent) {
archetypesCache.clear();
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(3, false));
createViewer(composite);
createAdvancedSettings(composite, new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
MavenPlugin.getIndexManager().addIndexListener(this);
setControl(composite);
}
/** Creates the archetype table viewer. */
@SuppressWarnings({"unchecked", "rawtypes"})
private void createViewer(Composite parent) {
Label catalogsLabel = new Label(parent, SWT.NONE);
catalogsLabel.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_lblCatalog);
Composite catalogsComposite = new Composite(parent, SWT.NONE);
GridLayout catalogsCompositeLayout = new GridLayout();
catalogsCompositeLayout.marginWidth = 0;
catalogsCompositeLayout.marginHeight = 0;
catalogsCompositeLayout.numColumns = 2;
catalogsComposite.setLayout(catalogsCompositeLayout);
catalogsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
catalogsComboViewer = new ComboViewer(catalogsComposite);
catalogsComboViewer.getControl().setData("name", "catalogsCombo"); //$NON-NLS-1$ //$NON-NLS-2$
catalogsComboViewer.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
catalogsComboViewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object input) {
if(input instanceof Collection) {
return ((Collection<?>) input).toArray();
}
return new Object[0];
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public void dispose() {
}
});
catalogsComboViewer.setLabelProvider(new LabelProvider() {
public String getText(Object element) {
if(element instanceof ArchetypeCatalogFactory) {
return ((ArchetypeCatalogFactory) element).getDescription();
} else if(element instanceof String) {
return element.toString();
}
return super.getText(element);
}
});
catalogsComboViewer.addSelectionChangedListener(event -> {
ISelection selection = event.getSelection();
boolean loadAll = false;
//hide previous archetypes when switching catalog
if(selection instanceof IStructuredSelection) {
Object factory = ((IStructuredSelection) selection).getFirstElement();
ArchetypeCatalogFactory newCatalogFactory = null;
if(factory instanceof ArchetypeCatalogFactory) {
newCatalogFactory = (ArchetypeCatalogFactory) factory;
}
if(factory != null && newCatalogFactory == null) {
loadAll = true;
} else if(Objects.equals(catalogFactory, newCatalogFactory) && viewer.getInput() != null) {
return;
}
catalogFactory = newCatalogFactory;
viewer.setInput(null);
reloadViewer();
} else {
loadAll = true;
}
if(loadAll) {
catalogFactory = null;
viewer.setInput(null);
loadArchetypes(null, null, null);
}
//remember what was switched to here
if(dialogSettings != null) {
if(catalogFactory != null)
dialogSettings.put(KEY_CATALOG, catalogFactory.getId());
else
dialogSettings.put(KEY_CATALOG, ALL_CATALOGS);
}
});
final ArchetypeManager archetypeManager = MavenPluginActivator.getDefault().getArchetypeManager();
ArrayList allCatalogs = new ArrayList(archetypeManager.getActiveArchetypeCatalogs());
allCatalogs.add(0, ALL_CATALOGS);
catalogsComboViewer.setInput(allCatalogs);
Button configureButton = new Button(catalogsComposite, SWT.NONE);
configureButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
configureButton.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_btnConfigure);
configureButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
Collection<ArchetypeCatalogFactory> oldCatalogs = archetypeManager.getActiveArchetypeCatalogs();
PreferencesUtil.createPreferenceDialogOn(getShell(),
"org.eclipse.m2e.core.preferences.MavenArchetypesPreferencePage", null, null).open(); //$NON-NLS-1$
Collection<ArchetypeCatalogFactory> newCatalogs = archetypeManager.getActiveArchetypeCatalogs();
//Deselect removed catalog if needed
if(catalogFactory != null && !newCatalogs.contains(catalogFactory)) {
catalogFactory = null;
}
//Select 1st new catalog
ArchetypeCatalogFactory selectedCatalog = catalogFactory;
for(ArchetypeCatalogFactory newCatalog : newCatalogs) {
if(!oldCatalogs.contains(newCatalog)) {
selectedCatalog = newCatalog;
break;
}
}
ArrayList allCatalogs1 = new ArrayList(newCatalogs);
allCatalogs1.add(0, ALL_CATALOGS);
catalogsComboViewer.setInput(allCatalogs1);
catalogsComboViewer
.setSelection(new StructuredSelection(selectedCatalog == null ? ALL_CATALOGS : selectedCatalog));
}));
Label filterLabel = new Label(parent, SWT.NONE);
filterLabel.setLayoutData(new GridData());
filterLabel.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_lblFilter);
QuickViewerFilter quickViewerFilter = new QuickViewerFilter();
VersionsFilter versionFilter = new VersionsFilter(DEFAULT_SHOW_LAST_VERSION, DEFAULT_INCLUDE_SNAPSHOTS);
filterText = new Text(parent, SWT.BORDER | SWT.SEARCH);
filterText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
filterText.addModifyListener(quickViewerFilter);
filterText.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.keyCode == SWT.ARROW_DOWN) {
viewer.getTable().setFocus();
viewer.getTable().setSelection(0);
viewer.setSelection(new StructuredSelection(viewer.getElementAt(0)), true);
}
}
});
ToolBar toolBar = new ToolBar(parent, SWT.FLAT);
toolBar.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
final ToolItem clearToolItem = new ToolItem(toolBar, SWT.PUSH);
clearToolItem.setEnabled(false);
clearToolItem.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ELCL_REMOVE));
clearToolItem
.setDisabledImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ELCL_REMOVE_DISABLED));
clearToolItem.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
filterText.setText(""); //$NON-NLS-1$
}));
filterText.addModifyListener(e -> clearToolItem.setEnabled(filterText.getText().length() > 0));
SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
GridData gd_sashForm = new GridData(SWT.FILL, SWT.FILL, false, true, 3, 1);
// gd_sashForm.widthHint = 500;
gd_sashForm.heightHint = 200;
sashForm.setLayoutData(gd_sashForm);
sashForm.setLayout(new GridLayout());
Composite composite1 = new Composite(sashForm, SWT.NONE);
GridLayout gridLayout1 = new GridLayout();
gridLayout1.horizontalSpacing = 0;
gridLayout1.marginWidth = 0;
gridLayout1.marginHeight = 0;
composite1.setLayout(gridLayout1);
viewer = new TableViewer(composite1, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
Table table = viewer.getTable();
table.setData("name", "archetypesTable"); //$NON-NLS-1$ //$NON-NLS-2$
table.setHeaderVisible(true);
TableColumn column1 = new TableColumn(table, SWT.LEFT);
column1.setWidth(150);
column1.setText(Messages.wizardProjectPageArchetypeColumnGroupId);
TableColumn column0 = new TableColumn(table, SWT.LEFT);
column0.setWidth(150);
column0.setText(Messages.wizardProjectPageArchetypeColumnArtifactId);
TableColumn column2 = new TableColumn(table, SWT.LEFT);
column2.setWidth(100);
column2.setText(Messages.wizardProjectPageArchetypeColumnVersion);
GridData tableData = new GridData(SWT.FILL, SWT.FILL, true, true);
tableData.widthHint = 400;
tableData.heightHint = 200;
table.setLayoutData(tableData);
viewer.setLabelProvider(new ArchetypeLabelProvider());
viewer.setComparator(new ViewerComparator() {
public int compare(Viewer viewer, Object e1, Object e2) {
return ARCHETYPE_COMPARATOR.compare((Archetype) e1, (Archetype) e2);
}
});
viewer.setComparer(new IElementComparer() {
public int hashCode(Object obj) {
if(obj instanceof Archetype) {
return ArchetypeUtil.getHashCode((Archetype) obj);
}
return obj.hashCode();
}
public boolean equals(Object one, Object another) {
if(one instanceof Archetype && another instanceof Archetype) {
return ArchetypeUtil.areEqual((Archetype) one, (Archetype) another);
}
return one.equals(another);
}
});
viewer.setFilters(new ViewerFilter[] {versionFilter, quickViewerFilter});
viewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object inputElement) {
if(inputElement instanceof Collection) {
return ((Collection<?>) inputElement).toArray();
}
return new Object[0];
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
});
viewer.addSelectionChangedListener(event -> {
Archetype archetype = getArchetype();
if(archetype != null) {
String repositoryUrl = archetype.getRepository();
String description = archetype.getDescription();
String text = description == null ? "" : description; //$NON-NLS-1$
text = text.replaceAll("\n", "").replaceAll("\\s{2,}", " "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if(repositoryUrl != null) {
text += text.length() > 0 ? "\n" + repositoryUrl : repositoryUrl; //$NON-NLS-1$
}
descriptionText.setText(text);
setPageComplete(true);
} else {
descriptionText.setText(""); //$NON-NLS-1$
setPageComplete(false);
}
});
viewer.addOpenListener(openevent -> {
if(canFlipToNextPage()) {
getContainer().showPage(getNextPage());
}
});
Composite composite2 = new Composite(sashForm, SWT.NONE);
GridLayout gridLayout2 = new GridLayout();
gridLayout2.marginHeight = 0;
gridLayout2.marginWidth = 0;
gridLayout2.horizontalSpacing = 0;
composite2.setLayout(gridLayout2);
descriptionText = new Text(composite2, SWT.WRAP | SWT.V_SCROLL | SWT.READ_ONLY | SWT.MULTI | SWT.BORDER);
GridData descriptionTextData = new GridData(SWT.FILL, SWT.FILL, true, true);
descriptionTextData.heightHint = 40;
descriptionText.setLayoutData(descriptionTextData);
//whole dialog resizes badly without the width hint to the desc text
descriptionTextData.widthHint = 250;
sashForm.setWeights(new int[] {80, 20});
Composite buttonComposite = new Composite(parent, SWT.NONE);
GridData gd_buttonComposite = new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1);
buttonComposite.setLayoutData(gd_buttonComposite);
GridLayout gridLayout = new GridLayout();
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
gridLayout.numColumns = 3;
buttonComposite.setLayout(gridLayout);
showLastVersionButton = new Button(buttonComposite, SWT.CHECK);
showLastVersionButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
showLastVersionButton.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_btnLast);
showLastVersionButton.setSelection(DEFAULT_SHOW_LAST_VERSION);
showLastVersionButton.addSelectionListener(versionFilter);
includeShapshotsButton = new Button(buttonComposite, SWT.CHECK);
GridData buttonData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
buttonData.horizontalIndent = 25;
includeShapshotsButton.setLayoutData(buttonData);
includeShapshotsButton
.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_btnSnapshots);
includeShapshotsButton.setSelection(DEFAULT_INCLUDE_SNAPSHOTS);
includeShapshotsButton.addSelectionListener(versionFilter);
addArchetypeButton = new Button(buttonComposite, SWT.NONE);
addArchetypeButton.setText(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_btnAdd);
addArchetypeButton.setData("name", "addArchetypeButton"); //$NON-NLS-1$ //$NON-NLS-2$
buttonData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
buttonData.horizontalIndent = 35;
addArchetypeButton.setLayoutData(buttonData);
addArchetypeButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
CustomArchetypeDialog dialog = new CustomArchetypeDialog(getShell(),
org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_add_title);
if(dialog.open() == Window.OK) {
String archetypeGroupId = dialog.getArchetypeGroupId();
String archetypeArtifactId = dialog.getArchetypeArtifactId();
String archetypeVersion = dialog.getArchetypeVersion();
String repositoryUrl = dialog.getRepositoryUrl();
downloadArchetype(archetypeGroupId, archetypeArtifactId, archetypeVersion, repositoryUrl);
}
}));
}
protected IWizardContainer getContainer() {
return super.getContainer();
}
public void addArchetypeSelectionListener(ISelectionChangedListener listener) {
viewer.addSelectionChangedListener(listener);
}
public void dispose() {
if(job != null) {
job.cancel();
job = null;
}
MavenPlugin.getIndexManager().removeIndexListener(this);
archetypesCache.clear();
super.dispose();
}
public List<Archetype> getArchetypesForCatalog() {
try {
return getArchetypesForCatalog(catalogFactory, null);
} catch(CoreException ce) {
setErrorMessage(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_error_read);
return null;
}
}
public List<Archetype> getArchetypesForCatalog(ArchetypeCatalogFactory archCatalogFactory, IProgressMonitor monitor)
throws CoreException {
if(archCatalogFactory == null) {
return getAllArchetypes(monitor);
}
String catalogId = archCatalogFactory.getId();
List<Archetype> archs = archetypesCache.get(catalogId);
if(archs == null) {
archs = archCatalogFactory.getArchetypeCatalog().getArchetypes();
if(archs == null) {
archs = Collections.emptyList();
}
archetypesCache.put(catalogId, archs);
}
return archs;
}
@SuppressWarnings("unchecked")
private List<Archetype> getAllArchetypes(IProgressMonitor monitor) {
ArchetypeManager manager = MavenPluginActivator.getDefault().getArchetypeManager();
Collection<ArchetypeCatalogFactory> archetypeCatalogs = manager.getActiveArchetypeCatalogs();
ArrayList<Archetype> list = new ArrayList<>();
if(monitor == null) {
monitor = new NullProgressMonitor();
}
for(ArchetypeCatalogFactory catalog : archetypeCatalogs) {
if(monitor.isCanceled()) {
return Collections.emptyList();
}
try {
//temporary hack to get around 'Test Remote Catalog' blowing up on download
//described in https://issues.sonatype.org/browse/MNGECLIPSE-1792
if(catalog.getDescription().startsWith("Test")) { //$NON-NLS-1$
continue;
}
@SuppressWarnings("rawtypes")
List arcs = getArchetypesForCatalog(catalog, monitor);
if(arcs != null) {
list.addAll(arcs);
}
} catch(Exception ce) {
log.error("Unable to read archetype catalog: " + catalog.getId(), ce); //$NON-NLS-1$
}
}
return list;
}
/** Loads the available archetypes. */
void loadArchetypes(final String groupId, final String artifactId, final String version) {
if(job != null) {
job.cancel();
}
job = new RetrievingArchetypesJob(catalogFactory);
job.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
final RetrievingArchetypesJob thisJob = (RetrievingArchetypesJob) event.getJob();
if(IStatus.CANCEL == event.getResult().getSeverity() || !isCurrentPage()) {
return;
}
List<Archetype> catalogArchetypes = thisJob.catalogArchetypes;
final String error;
if(IStatus.ERROR == event.getResult().getSeverity()) {
error = event.getResult().getMessage();
} else if((catalogArchetypes == null || catalogArchetypes.isEmpty())) {
ArchetypeManager archetypeManager = MavenPluginActivator.getDefault().getArchetypeManager();
Collection<ArchetypeCatalogFactory> catalogs = archetypeManager.getActiveArchetypeCatalogs();
if(catalogs.isEmpty()) {
error = Messages.MavenProjectWizardArchetypePage_error_noEnabledCatalogs;
} else if(catalogFactory != null && "Nexus Indexer".equals(catalogFactory.getDescription())) { //$NON-NLS-1$
error = Messages.MavenProjectWizardArchetypePage_error_emptyNexusIndexer;
} else {
error = Messages.MavenProjectWizardArchetypePage_error_emptyCatalog;
}
} else {
error = null;
}
Display.getDefault().asyncExec(() -> setErrorMessage(error));
TreeSet<Archetype> archs = new TreeSet<Archetype>(ARCHETYPE_COMPARATOR);
if(catalogArchetypes != null) {
archs.addAll(catalogArchetypes);
}
archetypes = archs;
Display.getDefault().asyncExec(() -> updateViewer(groupId, artifactId, version));
}
});
job.schedule();
}
private static String getArchetypeKey(Archetype archetype) {
return new StringBuilder(archetype.getGroupId()).append(":").append(archetype.getArtifactId()).toString(); //$NON-NLS-1$
}
ArchetypeCatalog getArchetypeCatalog() throws CoreException {
return catalogFactory == null ? null : catalogFactory.getArchetypeCatalog();
}
/** Sets the flag that the archetype selection is used in the wizard. */
public void setUsed(boolean isUsed) {
this.isUsed = isUsed;
}
/** Overrides the default to return "true" if the page is not used. */
public boolean isPageComplete() {
return !isUsed || super.isPageComplete();
}
/** Sets the focus to the table component. */
public void setVisible(boolean visible) {
super.setVisible(visible);
if(visible) {
ArchetypeManager archetypeManager = MavenPluginActivator.getDefault().getArchetypeManager();
String catalogId = dialogSettings.get(KEY_CATALOG);
catalogFactory = null;
if(catalogId != null && !catalogId.equals(ALL_CATALOGS)) {
catalogFactory = archetypeManager.getArchetypeCatalogFactory(catalogId);
}
if(catalogsComboViewer.getSelection().isEmpty()) {
catalogsComboViewer
.setSelection(new StructuredSelection(catalogFactory == null ? ALL_CATALOGS : catalogFactory));
}
viewer.getTable().setFocus();
Archetype selected = getArchetype();
if(selected != null) {
viewer.reveal(selected);
}
} else {
if(job != null) {
job.cancel();
job = null;
}
}
}
/** Returns the selected archetype. */
public Archetype getArchetype() {
return (Archetype) ((IStructuredSelection) viewer.getSelection()).getFirstElement();
}
void updateViewer(String groupId, String artifactId, String version) {
if(viewer.getControl().isDisposed()) {
return;
}
archetypeVersions = getArchetypeVersions(archetypes);
viewer.setInput(archetypes);
if(isCurrentPage()) {
selectArchetype(groupId, artifactId, version);
}
Table table = viewer.getTable();
int columnCount = table.getColumnCount();
int width = 0;
for(int i = 0; i < columnCount; i++ ) {
TableColumn column = table.getColumn(i);
column.pack();
width += column.getWidth();
}
GridData tableData = (GridData) table.getLayoutData();
int oldHint = tableData.widthHint;
if(width > oldHint) {
tableData.widthHint = width;
}
getShell().pack(true);
tableData.widthHint = oldHint;
}
private static Map<String, List<ArtifactVersion>> getArchetypeVersions(Collection<Archetype> archetypes) {
HashMap<String, List<ArtifactVersion>> archetypeVersions = new HashMap<>(archetypes.size());
HashMap<String, ArtifactVersion> versionFactory = new HashMap<>();
for(Archetype currentArchetype : archetypes) {
String version = currentArchetype.getVersion();
if(M2EUIUtils.nullOrEmpty(version)) {
// we don't know how to handle null/empty versions
continue;
}
String key = getArchetypeKey(currentArchetype);
List<ArtifactVersion> versions = archetypeVersions.get(key);
if(versions == null) {
versions = new ArrayList<ArtifactVersion>();
archetypeVersions.put(key, versions);
}
ArtifactVersion v = versionFactory.get(version);
if(v == null) {
v = new DefaultArtifactVersion(version);
versionFactory.put(version, v);
}
versions.add(v);
}
final Comparator<ArtifactVersion> comparator = (v1, v2) -> v2.compareTo(v1);
for(List<ArtifactVersion> versions : archetypeVersions.values()) {
Collections.sort(versions, comparator);
}
return archetypeVersions;
}
protected void selectArchetype(String groupId, String artifactId, String version) {
Archetype archetype = findArchetype(groupId, artifactId, version);
Table table = viewer.getTable();
if(archetype != null) {
viewer.setSelection(new StructuredSelection(archetype), true);
int n = table.getSelectionIndex();
table.setSelection(n);
}
}
/** Locates an archetype with given ids. */
protected Archetype findArchetype(String groupId, String artifactId, String version) {
for(Archetype archetype : archetypes) {
if(archetype.getGroupId().equals(groupId) && archetype.getArtifactId().equals(artifactId)) {
if(version == null || version.equals(archetype.getVersion())) {
return archetype;
}
}
}
return version == null ? null : findArchetype(groupId, artifactId, null);
}
protected void downloadArchetype(final String archetypeGroupId, final String archetypeArtifactId,
final String archetypeVersion, final String repositoryUrl) {
if(getContainer() == null) {
return;//page has been disposed
}
final String archetypeName = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion; //$NON-NLS-1$ //$NON-NLS-2$
try {
getContainer().run(true, true, monitor -> {
monitor.beginTask(
org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_task_downloading + archetypeName,
IProgressMonitor.UNKNOWN);
try {
final IMaven maven = MavenPlugin.getMaven();
final List<ArtifactRepository> remoteRepositories;
if(repositoryUrl.length() == 0) {
remoteRepositories = maven.getArtifactRepositories(); // XXX should use ArchetypeManager.getArchetypeRepositories()
} else {
//Use id = archetypeArtifactId+"-repo" to enable mirror/proxy authentication
//see http://maven.apache.org/archetype/maven-archetype-plugin/faq.html
ArtifactRepository repository = maven.createArtifactRepository(archetypeArtifactId + "-repo", //$NON-NLS-1$
repositoryUrl);
remoteRepositories = Collections.singletonList(repository);
}
monitor.subTask(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_task_resolving);
Artifact pomArtifact = maven.resolve(archetypeGroupId, archetypeArtifactId, archetypeVersion, "pom", null, //$NON-NLS-1$
remoteRepositories, monitor);
monitor.worked(1);
if(monitor.isCanceled()) {
throw new InterruptedException();
}
File pomFile = pomArtifact.getFile();
if(pomFile.exists()) {
monitor.subTask(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_task_resolving2);
Artifact jarArtifact = maven.resolve(archetypeGroupId, archetypeArtifactId, archetypeVersion, "jar", null, //$NON-NLS-1$
remoteRepositories, monitor);
monitor.worked(1);
if(monitor.isCanceled()) {
throw new InterruptedException();
}
File jarFile = jarArtifact.getFile();
monitor.subTask(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_task_reading);
monitor.worked(1);
if(monitor.isCanceled()) {
throw new InterruptedException();
}
monitor.subTask(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_task_indexing);
IndexManager indexManager = MavenPlugin.getIndexManager();
IMutableIndex localIndex = indexManager.getLocalIndex();
localIndex.addArtifact(jarFile, new ArtifactKey(pomArtifact));
//save out the archetype
//TODO move this logic out of UI code!
Archetype archetype = new Archetype();
archetype.setGroupId(archetypeGroupId);
archetype.setArtifactId(archetypeArtifactId);
archetype.setVersion(archetypeVersion);
archetype.setRepository(repositoryUrl);
org.apache.maven.archetype.ArchetypeManager archetyper = MavenPluginActivator.getDefault()
.getArchetypeManager().getArchetyper();
archetyper.updateLocalCatalog(archetype);
archetypesCache.clear();
loadArchetypes(archetypeGroupId, archetypeArtifactId, archetypeVersion);
} else {
final Artifact pom = pomArtifact;
//the user tried to add an archetype that couldn't be resolved on the server
getShell().getDisplay()
.asyncExec(() -> setErrorMessage(
NLS.bind(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_error_resolve,
pom.toString())));
}
} catch(InterruptedException ex1) {
throw ex1;
} catch(final Exception ex2) {
final String msg = NLS.bind(
org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_error_resolve2, archetypeName);
log.error(msg, ex2);
getShell().getDisplay().asyncExec(() -> setErrorMessage(msg + "\n" + ex2.toString()));
} finally {
monitor.done();
}
});
} catch(InterruptedException ex) {
// ignore
} catch(InvocationTargetException ex) {
String msg = NLS.bind(org.eclipse.m2e.core.ui.internal.Messages.MavenProjectWizardArchetypePage_error_resolve2,
archetypeName);
log.error(msg, ex);
setErrorMessage(msg + "\n" + ex.toString()); //$NON-NLS-1$
}
}
/**
* ArchetypeLabelProvider
*/
protected static class ArchetypeLabelProvider extends LabelProvider implements ITableLabelProvider {
/** Returns the element text */
public String getColumnText(Object element, int columnIndex) {
if(element instanceof Archetype) {
Archetype archetype = (Archetype) element;
switch(columnIndex) {
case 0:
return archetype.getGroupId();
case 1:
return archetype.getArtifactId();
case 2:
return archetype.getVersion();
}
}
return super.getText(element);
}
/** Returns the element text */
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
}
/**
* QuickViewerFilter
*/
protected class QuickViewerFilter extends ViewerFilter implements ModifyListener {
private String currentFilter;
public boolean select(Viewer viewer, Object parentElement, Object element) {
if(currentFilter == null || currentFilter.length() == 0) {
return true;
}
Archetype archetype = (Archetype) element;
return archetype.getGroupId().toLowerCase().indexOf(currentFilter) > -1
|| archetype.getArtifactId().toLowerCase().indexOf(currentFilter) > -1;
}
public void modifyText(ModifyEvent e) {
this.currentFilter = filterText.getText().trim().toLowerCase();
viewer.refresh();
}
}
protected class VersionsFilter extends ViewerFilter implements SelectionListener {
private boolean showLastVersion;
private boolean includeSnapshots;
public VersionsFilter(boolean showLastVersion, boolean includeSnapshots) {
this.showLastVersion = showLastVersion;
this.includeSnapshots = includeSnapshots;
}
public boolean select(Viewer viewer, Object parentElement, Object element) {
if(!(element instanceof Archetype)) {
return false;
}
Archetype archetype = (Archetype) element;
String version = archetype.getVersion();
if(!includeSnapshots) {
if(isSnapshotVersion(version)) {
return false;
}
}
if(!showLastVersion) {
return true;
}
// need to find latest version, skipping snapshots depending on includeSnapshots
List<ArtifactVersion> versions = archetypeVersions.get(getArchetypeKey(archetype));
if(versions == null || versions.isEmpty()) {
return false; // can't really happen
}
for(ArtifactVersion otherVersion : versions) {
if(includeSnapshots || !isSnapshotVersion(otherVersion.toString())) {
if(otherVersion.toString().equals(version)) {
return true;
}
break;
}
}
return false;
}
boolean isSnapshotVersion(String version) {
return !M2EUIUtils.nullOrEmpty(version) && version.endsWith("SNAPSHOT"); //$NON-NLS-1$
}
public void widgetSelected(SelectionEvent e) {
this.showLastVersion = showLastVersionButton.getSelection();
this.includeSnapshots = includeShapshotsButton.getSelection();
viewer.refresh();
Archetype archetype = getArchetype();
//can be null in some cases, don't try to reveal
if(archetype != null) {
viewer.reveal(archetype);
}
viewer.getTable().setSelection(viewer.getTable().getSelectionIndex());
viewer.getTable().setFocus();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
}
/* (non-Javadoc)
* @see org.eclipse.m2e.index.IndexListener#indexAdded(org.eclipse.m2e.repository.IRepository)
*/
public void indexAdded(IRepository repository) {
}
//reload the table when index updating finishes
//try to preserve selection in case this is a rebuild
protected void reloadViewer() {
Display.getDefault().asyncExec(() -> {
if(isCurrentPage()) {
StructuredSelection sel = (StructuredSelection) viewer.getSelection();
Archetype selArchetype = null;
if(sel != null && sel.getFirstElement() != null) {
selArchetype = (Archetype) sel.getFirstElement();
}
if(selArchetype != null) {
loadArchetypes(selArchetype.getGroupId(), selArchetype.getArtifactId(), selArchetype.getVersion());
} else {
loadArchetypes("org.apache.maven.archetypes", "maven-archetype-quickstart", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
});
}
/* (non-Javadoc)
* @see org.eclipse.m2e.index.IndexListener#indexChanged(org.eclipse.m2e.repository.IRepository)
*/
public void indexChanged(IRepository repository) {
reloadViewer();
}
/* (non-Javadoc)
* @see org.eclipse.m2e.index.IndexListener#indexRemoved(org.eclipse.m2e.repository.IRepository)
*/
public void indexRemoved(IRepository repository) {
}
/* (non-Javadoc)
* @see org.eclipse.m2e.index.IndexListener#indexUpdating(org.eclipse.m2e.repository.IRepository)
*/
public void indexUpdating(IRepository repository) {
}
private class RetrievingArchetypesJob extends Job {
List<Archetype> catalogArchetypes;
private ArchetypeCatalogFactory archetypeCatalogFactory;
public RetrievingArchetypesJob(ArchetypeCatalogFactory catalogFactory) {
super(Messages.wizardProjectPageArchetypeRetrievingArchetypes);
this.archetypeCatalogFactory = catalogFactory;
}
protected IStatus run(IProgressMonitor monitor) {
try {
catalogArchetypes = getArchetypesForCatalog(archetypeCatalogFactory, monitor);
} catch(Exception e) {
monitor.done();
return new Status(IStatus.ERROR, M2EUIPluginActivator.PLUGIN_ID,
Messages.MavenProjectWizardArchetypePage_ErrorRetrievingArchetypes, e);
}
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
}
}
}