blob: c2732d3c59c636c207a54b344eaba075a3d4f4ca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 The Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* The Eclipse Foundation - initial API and implementation
* Yatta Solutions - bug 314936, bug 398200, bug 432803: public API, bug 413871: performance
*******************************************************************************/
package org.eclipse.epp.internal.mpc.ui.catalog;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
import org.eclipse.epp.internal.mpc.core.ServiceLocator;
import org.eclipse.epp.internal.mpc.core.model.Identifiable;
import org.eclipse.epp.internal.mpc.core.model.Node;
import org.eclipse.epp.internal.mpc.core.model.SearchResult;
import org.eclipse.epp.internal.mpc.core.service.AbstractDataStorageService.NotAuthorizedException;
import org.eclipse.epp.internal.mpc.core.util.URLUtil;
import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory.Contents;
import org.eclipse.epp.internal.mpc.ui.catalog.UserActionCatalogItem.UserAction;
import org.eclipse.epp.mpc.core.model.ICategories;
import org.eclipse.epp.mpc.core.model.ICategory;
import org.eclipse.epp.mpc.core.model.IIdentifiable;
import org.eclipse.epp.mpc.core.model.IIu;
import org.eclipse.epp.mpc.core.model.IIus;
import org.eclipse.epp.mpc.core.model.IMarket;
import org.eclipse.epp.mpc.core.model.INews;
import org.eclipse.epp.mpc.core.model.INode;
import org.eclipse.epp.mpc.core.model.ISearchResult;
import org.eclipse.epp.mpc.core.service.IMarketplaceService;
import org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator;
import org.eclipse.epp.mpc.core.service.IMarketplaceStorageService;
import org.eclipse.epp.mpc.core.service.IMarketplaceStorageService.LoginListener;
import org.eclipse.epp.mpc.core.service.IUserFavoritesService;
import org.eclipse.epp.mpc.ui.CatalogDescriptor;
import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler;
import org.eclipse.equinox.internal.p2.discovery.AbstractDiscoveryStrategy;
import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory;
import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
import org.eclipse.equinox.internal.p2.discovery.model.Icon;
import org.eclipse.equinox.internal.p2.discovery.model.Overview;
import org.eclipse.equinox.internal.p2.discovery.model.Tag;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.userstorage.IStorage;
import org.eclipse.userstorage.oauth.EclipseOAuthCredentialsProvider;
import org.eclipse.userstorage.spi.ICredentialsProvider;
import org.osgi.framework.BundleContext;
/**
* @author David Green
* @author Carsten Reckord
*/
public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy {
private static final Pattern BREAK_PATTERN = Pattern.compile("<!--\\s*break\\s*-->"); //$NON-NLS-1$
protected final CatalogDescriptor catalogDescriptor;
protected final IMarketplaceService marketplaceService;
private MarketplaceCatalogSource source;
private MarketplaceInfo marketplaceInfo;
private Map<String, IInstallableUnit> featureIUById;
private List<LoginListener> loginListeners;
private IShellProvider shellProvider;
public MarketplaceDiscoveryStrategy(CatalogDescriptor catalogDescriptor) {
if (catalogDescriptor == null) {
throw new IllegalArgumentException();
}
this.catalogDescriptor = catalogDescriptor;
marketplaceService = createMarketplaceService();//use deprecated method in case someone has overridden it
source = new MarketplaceCatalogSource(marketplaceService);
marketplaceInfo = MarketplaceInfo.getInstance();
}
/**
* @deprecated get a marketplace service from the registered {@link IMarketplaceServiceLocator} OSGi service instead
*/
@Deprecated
public IMarketplaceService createMarketplaceService() {
return acquireMarketplaceService();
}
protected IMarketplaceService acquireMarketplaceService() {
String baseUrl = this.catalogDescriptor.getUrl().toExternalForm();
return ServiceLocator.getCompatibilityLocator().getMarketplaceService(baseUrl);
}
/**
* @deprecated moved to {@link ServiceLocator#computeDefaultRequestMetaParameters()}
*/
@Deprecated
public static Map<String, String> computeDefaultRequestMetaParameters() {
return ServiceLocator.computeDefaultRequestMetaParameters();
}
@Override
public void dispose() {
List<LoginListener> loginListeners = this.loginListeners;
this.loginListeners = null;
if (loginListeners != null) {
IUserFavoritesService favoritesService = marketplaceService.getUserFavoritesService();
if (favoritesService != null) {
IMarketplaceStorageService storageService = favoritesService.getStorageService();
for (LoginListener loginListener : loginListeners) {
storageService.removeLoginListener(loginListener);
}
}
}
if (source != null) {
source.dispose();
source = null;
}
if (marketplaceInfo != null) {
final MarketplaceInfo fMarketplaceInfo = marketplaceInfo;
new Job(Messages.MarketplaceDiscoveryStrategy_saveMarketplaceInfoJobName) {
{
setSystem(true);
setPriority(SHORT);
setUser(false);
}
@Override
public boolean belongsTo(Object family) {
BundleContext bundleContext = MarketplaceClientUiPlugin.getBundleContext();
MarketplaceClientUiPlugin plugin = MarketplaceClientUiPlugin.getInstance();
return (bundleContext != null && (family == bundleContext || family == bundleContext.getBundle()))
|| (plugin != null && family == plugin);
}
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
fMarketplaceInfo.save();
} catch (Exception e) {
return MarketplaceClientCore.computeStatus(e, Messages.MarketplaceDiscoveryStrategy_failedToSaveMarketplaceInfo);
}
return Status.OK_STATUS;
}
}.schedule();
marketplaceInfo = null;
}
super.dispose();
}
public synchronized void addLoginListener(LoginListener loginListener) {
IUserFavoritesService favoritesService = marketplaceService.getUserFavoritesService();
if (favoritesService != null) {
if (loginListeners == null) {
loginListeners = new CopyOnWriteArrayList<>();
}
if (!loginListeners.contains(loginListener)) {
loginListeners.add(loginListener);
IMarketplaceStorageService storageService = favoritesService.getStorageService();
storageService.addLoginListener(loginListener);
}
}
}
public synchronized void removeLoginListener(LoginListener loginListener) {
if (loginListeners != null) {
loginListeners.remove(loginListener);
}
IUserFavoritesService favoritesService = marketplaceService.getUserFavoritesService();
if (favoritesService != null) {
IMarketplaceStorageService storageService = favoritesService.getStorageService();
storageService.removeLoginListener(loginListener);
}
}
protected void applyShellProvider() {
IUserFavoritesService userFavoritesService = marketplaceService.getUserFavoritesService();
if (userFavoritesService == null) {
return;
}
IMarketplaceStorageService storageService = userFavoritesService.getStorageService();
if (storageService == null) {
return;
}
IStorage storage = storageService.getStorage();
ICredentialsProvider credentialsProvider = storage.getCredentialsProvider();
if (credentialsProvider instanceof EclipseOAuthCredentialsProvider) {
((EclipseOAuthCredentialsProvider) credentialsProvider).setShell(shellProvider);
}
}
public boolean hasUserFavoritesService() {
return marketplaceService.getUserFavoritesService() != null;
}
@Override
public void performDiscovery(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_loadingMarketplace,
3000);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1000));
handleDiscoveryCategory(catalogCategory);
ISearchResult discoveryResult = doPerformDiscovery(progress.newChild(1000));
handleSearchResult(catalogCategory, discoveryResult, progress.newChild(1000));
maybeAddCatalogItem(catalogCategory);
} finally {
monitor.done();
}
}
protected ISearchResult doPerformDiscovery(IProgressMonitor monitor) throws CoreException {
return marketplaceService.featured(monitor);
}
protected void handleDiscoveryCategory(MarketplaceCategory catalogCategory) {
catalogCategory.setContents(Contents.FEATURED);
}
protected void handleSearchResult(MarketplaceCategory catalogCategory, ISearchResult result,
final IProgressMonitor monitor) {
List<CatalogItem> items = getItems();
if (items != null && !result.getNodes().isEmpty()) {
int nodeWork = 1000;
int favoritesWork = catalogCategory.getContents() == Contents.USER_FAVORITES ? 0 : 1000;
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_loadingResources,
result.getNodes().size() * nodeWork + favoritesWork);
try {
boolean userFavoritesSupported = false;
if (catalogCategory.getContents() == Contents.USER_FAVORITES) {
userFavoritesSupported = true;
} else if (hasUserFavoritesService()) {
try {
applyShellProvider();
marketplaceService.userFavorites(result.getNodes(), progress.newChild(favoritesWork));
userFavoritesSupported = true;
} catch (NotAuthorizedException e1) {
// user is not logged in. we just ignore this.
} catch (UnsupportedOperationException e1) {
// ignore
} catch (Exception e1) {
// something went wrong. log and proceed.
MarketplaceClientCore.error(Messages.MarketplaceDiscoveryStrategy_FavoritesRetrieveError, e1);
}
}
for (final INode node : result.getNodes()) {
CatalogItem catalogItem = createCatalogItem(node, catalogCategory.getId(), userFavoritesSupported,
progress.newChild(nodeWork));
items.add(catalogItem);
}
} finally {
progress.done();
}
if (result.getMatchCount() != null) {
catalogCategory.setMatchCount(result.getMatchCount());
if (result.getMatchCount() > result.getNodes().size()) {
// add an item here to indicate that the search matched more items than were returned by the server
addCatalogItem(catalogCategory);
}
}
}
}
protected CatalogItem createCatalogItem(final INode node, String categoryId, boolean userFavoritesSupported,
IProgressMonitor monitor) {
String id = node.getId();
try {
final MarketplaceNodeCatalogItem catalogItem = new MarketplaceNodeCatalogItem();
catalogItem.setMarketplaceUrl(catalogDescriptor.getUrl());
catalogItem.setId(id);
catalogItem.setName(getCatalogItemName(node));
catalogItem.setCategoryId(categoryId);
ICategories categories = node.getCategories();
if (categories != null) {
for (ICategory category : categories.getCategory()) {
catalogItem.addTag(new Tag(ICategory.class, category.getId(), category.getName()));
}
}
catalogItem.setData(node);
catalogItem.setSource(source);
catalogItem.setLicense(node.getLicense());
catalogItem.setUserFavorite(userFavoritesSupported ? node.getUserFavorite() : null);
IIus ius = node.getIus();
if (ius != null) {
List<MarketplaceNodeInstallableUnitItem> installableUnitItems = new ArrayList<>();
for (IIu iu : ius.getIuElements()) {
MarketplaceNodeInstallableUnitItem iuItem = new MarketplaceNodeInstallableUnitItem();
iuItem.init(iu);
installableUnitItems.add(iuItem);
}
catalogItem.setInstallableUnitItems(installableUnitItems);
}
if (node.getShortdescription() == null && node.getBody() != null) {
// bug 306653 <!--break--> marks the end of the short description.
String descriptionText = node.getBody();
Matcher matcher = BREAK_PATTERN.matcher(node.getBody());
if (matcher.find()) {
int start = matcher.start();
if (start > 0) {
String shortDescriptionText = descriptionText.substring(0, start).trim();
if (shortDescriptionText.length() > 0) {
descriptionText = shortDescriptionText;
}
}
}
catalogItem.setDescription(descriptionText);
} else {
catalogItem.setDescription(node.getShortdescription());
}
catalogItem.setProvider(node.getCompanyname());
String updateurl = node.getUpdateurl();
if (updateurl != null) {
try {
// trim is important!
updateurl = updateurl.trim();
URLUtil.toURL(updateurl);
catalogItem.setSiteUrl(updateurl);
} catch (MalformedURLException e) {
// don't use malformed URLs
}
}
if (catalogItem.getInstallableUnits() == null || catalogItem.getInstallableUnits().isEmpty()
|| catalogItem.getSiteUrl() == null) {
catalogItem.setAvailable(false);
}
if (node.getImage() != null) {
if (!source.getResourceProvider().containsResource(node.getImage())) {
cacheResource(source.getResourceProvider(), catalogItem, node.getImage());
}
createIcon(catalogItem, node);
}
if (node.getBody() != null || node.getScreenshot() != null) {
final Overview overview = new Overview();
overview.setItem(catalogItem);
overview.setSummary(node.getBody());
overview.setUrl(node.getUrl());
catalogItem.setOverview(overview);
if (node.getScreenshot() != null) {
if (!source.getResourceProvider().containsResource(node.getScreenshot())) {
cacheResource(source.getResourceProvider(), catalogItem, node.getScreenshot());
}
overview.setScreenshot(node.getScreenshot());
}
}
marketplaceInfo.map(catalogItem.getMarketplaceUrl(), node);
marketplaceInfo.computeInstalled(computeInstalledFeatures(monitor),
catalogItem);
return catalogItem;
} catch (RuntimeException ex) {
MarketplaceClientUi.error(
NLS.bind(Messages.MarketplaceDiscoveryStrategy_ParseError,
node == null ? "null" : id), //$NON-NLS-1$
ex);
return null;
}
}
public static void cacheResource(ResourceProvider resourceProvider, CatalogItem catalogItem,
String resource) {
if (!resourceProvider.containsResource(resource)) {
String requestSource = NLS.bind(Messages.MarketplaceDiscoveryStrategy_requestSource, catalogItem.getName(), catalogItem.getId());
try {
resourceProvider.retrieveResource(requestSource, resource);
} catch (URISyntaxException e) {
MarketplaceClientUi.log(IStatus.WARNING, Messages.MarketplaceDiscoveryStrategy_badUri,
catalogItem.getName(),
catalogItem.getId(), resource, e);
} catch (IOException e) {
MarketplaceClientUi.log(IStatus.WARNING, Messages.MarketplaceDiscoveryStrategy_downloadError,
catalogItem.getName(),
catalogItem.getId(), resource, e);
}
}
}
private static String getCatalogItemName(INode node) {
String name = node.getName();
String version = node.getVersion();
return version == null || version.length() == 0 ? name : NLS.bind(
Messages.MarketplaceDiscoveryStrategy_Name_and_Version, name, version);
}
public void maybeAddCatalogItem(MarketplaceCategory catalogCategory) {
List<CatalogItem> items = getItems();
if (items != null && !items.isEmpty()) {
CatalogItem catalogItem = items.get(items.size() - 1);
if (catalogItem.getData() != catalogDescriptor) {
addCatalogItem(catalogCategory);
}
}
}
public void addCatalogItem(MarketplaceCategory catalogCategory) {
CatalogItem catalogItem = createCategoryItem(catalogCategory);
items.add(catalogItem);
}
private CatalogItem createCategoryItem(MarketplaceCategory catalogCategory) {
CatalogItem catalogItem = new CatalogItem();
catalogItem.setSource(source);
catalogItem.setData(catalogDescriptor);
catalogItem.setId(catalogDescriptor.getUrl().toString());
catalogItem.setCategoryId(catalogCategory.getId());
return catalogItem;
}
public UserActionCatalogItem addUserActionItem(MarketplaceCategory catalogCategory, UserAction userAction) {
return addUserActionItem(catalogCategory, userAction, catalogDescriptor);
}
public UserActionCatalogItem addUserActionItem(MarketplaceCategory catalogCategory, UserAction userAction,
Object data) {
for (ListIterator<CatalogItem> i = items.listIterator(items.size()); i.hasPrevious();) {
CatalogItem item = i.previous();
if (item.getSource() == source && (item.getCategory() == catalogCategory || catalogCategory.getId().equals(item.getCategoryId()))
&& item instanceof UserActionCatalogItem) {
UserActionCatalogItem actionItem = (UserActionCatalogItem) item;
if (actionItem.getUserAction() == userAction) {
return actionItem;
}
}
}
UserActionCatalogItem catalogItem = new UserActionCatalogItem();
catalogItem.setUserAction(userAction);
catalogItem.setSource(source);
catalogItem.setData(data);
catalogItem.setId(catalogDescriptor.getUrl().toString() + "#" + userAction.name()); //$NON-NLS-1$
catalogItem.setCategoryId(catalogCategory.getId());
items.add(0, catalogItem);
return catalogItem;
}
private static void createIcon(CatalogItem catalogItem, final INode node) {
Icon icon = new Icon();
// don't know the size
icon.setImage32(node.getImage());
icon.setImage48(node.getImage());
icon.setImage64(node.getImage());
icon.setImage128(node.getImage());
catalogItem.setIcon(icon);
}
public void tagged(String tag, IProgressMonitor monitor) throws CoreException {
final int totalWork = 1000;
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
totalWork);
try {
ISearchResult result;
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.QUERY);
//resolve market and category if necessary
result = marketplaceService.tagged(tag, progress.newChild(500));
handleSearchResult(catalogCategory, result, progress.newChild(500));
if (result.getNodes().isEmpty()) {
catalogCategory.setMatchCount(0);
addCatalogItem(catalogCategory);
}
} finally {
progress.done();
}
}
public void performQuery(IMarket market, ICategory category, String queryText, IProgressMonitor monitor)
throws CoreException {
final int totalWork = 1001;
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
totalWork);
try {
ISearchResult result;
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.QUERY);
SubMonitor nodeQueryProgress = progress.newChild(500);
try {
//check if the query matches a node url and just retrieve that node
result = performNodeQuery(queryText, nodeQueryProgress);
} catch (CoreException ex) {
// node not found, continue with regular query
result = null;
//no work was done
nodeQueryProgress.setWorkRemaining(0);
}
if (result == null) {
//regular query
//resolve market and category if necessary
IMarket resolvedMarket;
ICategory resolvedCategory;
try {
resolvedMarket = resolve(market, catalogCategory.getMarkets());
resolvedCategory = resolveCategory(category, catalogCategory.getMarkets());
} catch (IllegalArgumentException ex) {
throw new CoreException(MarketplaceClientCore.computeStatus(ex, Messages.MarketplaceDiscoveryStrategy_invalidFilter));
} catch (NoSuchElementException ex) {
throw new CoreException(MarketplaceClientCore.computeStatus(ex, Messages.MarketplaceDiscoveryStrategy_unknownFilter));
}
progress.setWorkRemaining(totalWork - 1);
result = marketplaceService.search(resolvedMarket, resolvedCategory, queryText, progress.newChild(500));
}
handleSearchResult(catalogCategory, result, progress.newChild(500));
if (result.getNodes().isEmpty()) {
catalogCategory.setMatchCount(0);
addCatalogItem(catalogCategory);
}
} finally {
progress.done();
}
}
private static ICategory resolveCategory(ICategory category, List<? extends IMarket> markets)
throws IllegalArgumentException, NoSuchElementException {
if (category != null && category.getId() == null) {
//need to resolve
if (category.getUrl() == null && category.getName() == null) {
throw new IllegalArgumentException(NLS.bind(Messages.MarketplaceDiscoveryStrategy_unidentifiableItem,
category));
}
for (IMarket market : markets) {
List<? extends ICategory> categories = market.getCategory();
ICategory resolved = resolve(category, categories);
if (resolved != null) {
return resolved;
}
}
if (category.getUrl() != null) {
throw new NoSuchElementException(NLS.bind(Messages.MarketplaceDiscoveryStrategy_noUrlMatch,
category.getUrl()));
} else {
throw new NoSuchElementException(NLS.bind(Messages.MarketplaceDiscoveryStrategy_noNameMatch,
category.getName()));
}
}
return category;
}
private static <T extends IIdentifiable> T resolve(T id, List<? extends T> candidates)
throws IllegalArgumentException,
NoSuchElementException {
if (id != null && id.getId() == null) {
//need to resolve
if (id.getUrl() == null && id.getName() == null) {
throw new IllegalArgumentException(NLS.bind(
Messages.MarketplaceDiscoveryStrategy_unidentifiableItem, id));
}
for (T candidate : candidates) {
if (Identifiable.matches(candidate, id)) {
return candidate;
}
}
if (id.getUrl() != null) {
throw new NoSuchElementException(NLS.bind(Messages.MarketplaceDiscoveryStrategy_noUrlMatch, id.getUrl()));
} else {
throw new NoSuchElementException(NLS.bind(Messages.MarketplaceDiscoveryStrategy_noNameMatch, id.getName()));
}
}
return id;
}
private ISearchResult performNodeQuery(String nodeUrl, IProgressMonitor progress) throws CoreException {
final INode[] queryNode = new INode[1];
MarketplaceUrlHandler urlHandler = new MarketplaceUrlHandler() {
@Override
protected boolean handleNode(CatalogDescriptor descriptor, String url, INode node) {
queryNode[0] = node;
return true;
}
};
if (urlHandler.handleUri(nodeUrl) && queryNode[0] != null) {
INode node = marketplaceService.getNode(queryNode[0], progress);
SearchResult result = new SearchResult();
result.setMatchCount(1);
result.setNodes(Collections.singletonList((Node) node));
return result;
}
return null;
}
public void recent(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.RECENT);
ISearchResult result = marketplaceService.recent(progress.newChild(500));
handleSearchResult(catalogCategory, result, progress.newChild(500));
maybeAddCatalogItem(catalogCategory);
} finally {
monitor.done();
}
}
public void related(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
801);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.RELATED);
SearchResult installed = computeInstalled(progress.newChild(200));
if (!monitor.isCanceled()) {
ISearchResult result = marketplaceService.related(installed.getNodes(),
progress.newChild(300));
handleSearchResult(catalogCategory, result, progress.newChild(300));
maybeAddCatalogItem(catalogCategory);
}
} finally {
monitor.done();
}
}
public void featured(IProgressMonitor monitor, final IMarket market, final ICategory category) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.FEATURED);
ISearchResult result = marketplaceService.featured(market, category, progress.newChild(500));
handleSearchResult(catalogCategory, result, progress.newChild(500));
maybeAddCatalogItem(catalogCategory);
} finally {
monitor.done();
}
}
public void popular(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.POPULAR);
ISearchResult result = marketplaceService.popular(progress.newChild(500));
handleSearchResult(catalogCategory, result, progress.newChild(500));
maybeAddCatalogItem(catalogCategory);
} finally {
monitor.done();
}
}
public void userFavorites(boolean promptLogin, IProgressMonitor monitor) throws CoreException {
final SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_FavoritesRetrieve, 1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.USER_FAVORITES);
IUserFavoritesService userFavoritesService = marketplaceService.getUserFavoritesService();
if (userFavoritesService != null) {
try {
applyShellProvider();
ISearchResult result;
if (promptLogin) {
IMarketplaceStorageService storageService = userFavoritesService.getStorageService();
result = storageService
.runWithLogin(() -> marketplaceService.userFavorites(progress.newChild(500)));
} else {
result = marketplaceService.userFavorites(progress.newChild(500));
}
if (result.getNodes().isEmpty()) {
catalogCategory = addPopularItems(progress.newChild(500));
addNoFavoritesItem(catalogCategory);
} else {
handleSearchResult(catalogCategory, result, progress.newChild(500));
}
} catch (NotAuthorizedException e) {
catalogCategory = addPopularItems(progress.newChild(500));
addUserStorageLoginItem(catalogCategory, e.getLocalizedMessage());
} catch (UnsupportedOperationException ex) {
catalogCategory = addPopularItems(progress.newChild(500));
addFavoritesNotSupportedItem(catalogCategory);
} catch (Exception ex) {
//FIXME we should use the wizard page's status line to show errors, but that's unreachable from here...
MarketplaceClientCore.error(Messages.MarketplaceDiscoveryStrategy_FavoritesRetrieveError, ex);
catalogCategory = addPopularItems(progress.newChild(500));
addRetryErrorItem(catalogCategory, ex);
}
} else {
catalogCategory = addPopularItems(progress.newChild(1000));
addFavoritesNotSupportedItem(catalogCategory);
}
} finally {
monitor.done();
}
}
private MarketplaceCategory addPopularItems(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, 100);
MarketplaceCategory catalogCategory;
popular(progress.newChild(99));
catalogCategory = findMarketplaceCategory(progress.newChild(1));
return catalogCategory;
}
public void refreshUserFavorites(IProgressMonitor monitor) throws CoreException {
final SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_FavoritesRefreshing, 1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
List<CatalogItem> items = catalogCategory.getItems();
if (hasUserFavoritesService()) {
Map<String, INode> nodes = new HashMap<>();
for (CatalogItem item : items) {
Object data = item.getData();
if (data instanceof INode) {
INode node = (INode) data;
nodes.put(node.getId(), node);
}
}
if (nodes.isEmpty()) {
return;
}
try {
applyShellProvider();
marketplaceService.userFavorites(new ArrayList<>(nodes.values()), progress.newChild(500));
for (CatalogItem catalogItem : items) {
if (catalogItem instanceof MarketplaceNodeCatalogItem) {
MarketplaceNodeCatalogItem nodeItem = (MarketplaceNodeCatalogItem) catalogItem;
INode node = nodes.get(nodeItem.getId());
nodeItem.setUserFavorite(node == null ? null : node.getUserFavorite());
}
}
} catch (NotAuthorizedException e) {
catalogCategory = addPopularItems(progress.newChild(500));
addUserStorageLoginItem(catalogCategory, e.getLocalizedMessage());
} catch (UnsupportedOperationException ex) {
catalogCategory = addPopularItems(progress.newChild(500));
addFavoritesNotSupportedItem(catalogCategory);
} catch (Exception ex) {
//FIXME we should use the wizard page's status line to show errors, but that's unreachable from here...
MarketplaceClientCore.error(Messages.MarketplaceDiscoveryStrategy_FavoritesRetrieveError, ex);
catalogCategory = addPopularItems(progress.newChild(500));
addRetryErrorItem(catalogCategory, ex);
}
} else {
for (CatalogItem catalogItem : items) {
if (catalogItem instanceof MarketplaceNodeCatalogItem) {
MarketplaceNodeCatalogItem nodeItem = (MarketplaceNodeCatalogItem) catalogItem;
nodeItem.setUserFavorite(null);
}
}
}
} finally {
monitor.done();
}
}
private void addUserStorageLoginItem(MarketplaceCategory catalogCategory, String authMessage) {
addUserActionItem(catalogCategory, UserAction.LOGIN, authMessage);
}
private void addNoFavoritesItem(MarketplaceCategory catalogCategory) {
addUserActionItem(catalogCategory, UserAction.CREATE_FAVORITES);
}
private void addFavoritesNotSupportedItem(MarketplaceCategory catalogCategory) {
addUserActionItem(catalogCategory, UserAction.FAVORITES_UNSUPPORTED);
}
private void addRetryErrorItem(MarketplaceCategory catalogCategory, Exception ex) {
addUserActionItem(catalogCategory, UserAction.RETRY_ERROR, ex);
}
public void addOpenFavoritesItem(MarketplaceCategory catalogCategory) {
addUserActionItem(catalogCategory, UserAction.OPEN_FAVORITES);
}
public void addUpdateItem(MarketplaceCategory catalogCategory, List<MarketplaceNodeCatalogItem> availableUpdates) {
addUserActionItem(catalogCategory, UserAction.UPDATE, availableUpdates);
}
public void installed(IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_findingInstalled,
1000);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.INSTALLED);
SearchResult result = computeInstalled(progress.newChild(500));
if (!monitor.isCanceled()) {
handleSearchResult(catalogCategory, result, progress.newChild(500));
}
} finally {
monitor.done();
}
}
protected SearchResult computeInstalled(IProgressMonitor monitor) throws CoreException {
SearchResult result = new SearchResult();
result.setNodes(new ArrayList<Node>());
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_ComputingInstalled, 1000);
Map<String, IInstallableUnit> installedIUs = computeInstalledIUs(progress.newChild(500));
if (!monitor.isCanceled()) {
Set<INode> catalogNodes = marketplaceInfo.computeInstalledNodes(catalogDescriptor.getUrl(), installedIUs);
if (!catalogNodes.isEmpty()) {
List<INode> resolvedNodes = marketplaceService.getNodes(catalogNodes, progress.newChild(490));
Map<String, INode> uniqueNodes = new HashMap<>();
SubMonitor nodeProgress = SubMonitor.convert(progress.newChild(10), resolvedNodes.size());
for (INode node : resolvedNodes) {
boolean duplicate = node.getId() != null && uniqueNodes.put(node.getId(), node) != null;
//previous result on rhs to avoid shortcut behavior
duplicate = (node.getUrl() != null && uniqueNodes.put(node.getUrl(), node) != null) || duplicate;
//compute real installed state based on optional/required state
if (!duplicate && marketplaceInfo.computeInstalled(installedIUs.keySet(), node)) {
result.getNodes().add((Node) node);
}
nodeProgress.worked(1);
}
} else {
monitor.worked(500);
}
}
return result;
}
public void performQuery(IProgressMonitor monitor, Set<String> nodeIds) throws CoreException {
Set<INode> nodes = new HashSet<>();
for (String nodeId : nodeIds) {
Node node = new Node();
node.setId(nodeId);
nodes.add(node);
}
performNodeQuery(monitor, nodes);
}
public void performNodeQuery(IProgressMonitor monitor, Set<? extends INode> nodes) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace,
1001);
try {
MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1));
catalogCategory.setContents(Contents.QUERY);
SearchResult result = new SearchResult();
result.setNodes(new ArrayList<Node>());
if (!monitor.isCanceled()) {
if (!nodes.isEmpty()) {
List<INode> resolvedNodes = marketplaceService.getNodes(nodes, progress.newChild(500));
for (INode node : resolvedNodes) {
result.getNodes().add((Node) node);
}
} else {
progress.setWorkRemaining(500);
}
result.setMatchCount(result.getNodes().size());
handleSearchResult(catalogCategory, result, progress.newChild(500));
}
} finally {
monitor.done();
}
}
/**
* @deprecated use {@link #computeInstalledIUs(IProgressMonitor)} instead
*/
@Deprecated
protected Set<String> computeInstalledFeatures(IProgressMonitor monitor) {
return computeInstalledIUs(monitor).keySet();
}
protected synchronized Map<String, IInstallableUnit> computeInstalledIUs(IProgressMonitor monitor) {
if (featureIUById == null) {
featureIUById = MarketplaceClientUi.computeInstalledIUsById(monitor);
}
return featureIUById;
}
protected MarketplaceCategory findMarketplaceCategory(IProgressMonitor monitor) throws CoreException {
MarketplaceCategory catalogCategory = null;
SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_catalogCategory, 10000);
try {
List<CatalogCategory> categories = getCategories();
if (categories == null) {
categories = new ArrayList<CatalogCategory>();
setCategories(categories);
}
for (CatalogCategory candidate : categories) {
if (candidate.getSource() == source) {
catalogCategory = (MarketplaceCategory) candidate;
}
}
if (catalogCategory == null) {
List<? extends IMarket> markets = marketplaceService.listMarkets(progress.newChild(10000));
// marketplace has markets and categories, however a node and/or category can appear in multiple
// markets. This doesn't match well with discovery's concept of a category. Discovery requires all
// items to be in a category, so we use a single root category and tagging.
catalogCategory = new MarketplaceCategory();
catalogCategory.setId("<root>"); //$NON-NLS-1$
catalogCategory.setName("<root>"); //$NON-NLS-1$
catalogCategory.setSource(source);
catalogCategory.setMarkets(markets);
categories.add(catalogCategory);
}
} finally {
progress.done();
}
return catalogCategory;
}
public INews performNewsDiscovery(IProgressMonitor monitor) throws CoreException {
return marketplaceService.news(monitor);
}
public void installErrorReport(IProgressMonitor monitor, IStatus result, Set<CatalogItem> items,
IInstallableUnit[] operationIUs, String resolutionDetails) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor,
Messages.MarketplaceDiscoveryStrategy_sendingErrorNotification, 100);
try {
Set<Node> nodes = new HashSet<>();
for (CatalogItem item : items) {
Object data = item.getData();
if (data instanceof INode) {
nodes.add((Node) data);
}
}
Set<String> iuIdsAndVersions = new HashSet<>();
for (IInstallableUnit iu : operationIUs) {
String id = iu.getId();
String version = iu.getVersion() == null ? null : iu.getVersion().toString();
iuIdsAndVersions.add(id + "," + version); //$NON-NLS-1$
}
marketplaceService.reportInstallError(result, nodes, iuIdsAndVersions, resolutionDetails, progress);
} finally {
progress.done();
}
}
public IMarketplaceService getMarketplaceService() {
return marketplaceService;
}
protected MarketplaceCatalogSource getCatalogSource() {
return source;
}
public void setShellProvider(IShellProvider shellProvider) {
this.shellProvider = shellProvider;
applyShellProvider();
}
public IShellProvider getShellProvider() {
return shellProvider;
}
}