diff options
author | Carsten Reckord | 2014-04-03 10:31:19 +0000 |
---|---|---|
committer | Carsten Reckord | 2014-04-16 10:18:14 +0000 |
commit | 3a32f6c8b907a77a778ce90c507c28b7a514f5c7 (patch) | |
tree | 888d8e31e021c10f81d993a52ff842a0168e239d | |
parent | 1cfe332fd8b1e74f24f99520d0b39d34e81a4c26 (diff) | |
download | org.eclipse.epp.mpc-3a32f6c8b907a77a778ce90c507c28b7a514f5c7.tar.gz org.eclipse.epp.mpc-3a32f6c8b907a77a778ce90c507c28b7a514f5c7.tar.xz org.eclipse.epp.mpc-3a32f6c8b907a77a778ce90c507c28b7a514f5c7.zip |
432803: Public API for the Marketplace Client
- extracted core API data model
- extracted core API services as OSGi services
- defined UI API services and extracted relevant UI models to public API
- additional SWTBot tests for UI services
Bug: 432803
Change-Id: Ie4fedd26c24b6cee06572781ca44ceea72984a91
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=432803
135 files changed, 5238 insertions, 1234 deletions
diff --git a/org.eclipse.epp.mpc-target/kepler.target b/org.eclipse.epp.mpc-target/kepler.target index 9faaf50c..016108dc 100644 --- a/org.eclipse.epp.mpc-target/kepler.target +++ b/org.eclipse.epp.mpc-target/kepler.target @@ -1,19 +1,22 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
-<target name="Kepler" sequenceNumber="10">
+<target name="MPC Target Platform - Kepler" sequenceNumber="10">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
<unit id="org.eclipse.equinox.p2.discovery.feature.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.rcp.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/releases/kepler"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.license.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/cbi/updates/license"/>
</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.swtbot.generator.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/technology/swtbot/releases/latest"/>
+</location>
</locations>
</target>
diff --git a/org.eclipse.epp.mpc-target/luna.target b/org.eclipse.epp.mpc-target/luna.target index c0ef1087..dfa45803 100644 --- a/org.eclipse.epp.mpc-target/luna.target +++ b/org.eclipse.epp.mpc-target/luna.target @@ -1,19 +1,22 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
-<target name="luna" sequenceNumber="0">
+<target name="MPC Target Platform - Luna" sequenceNumber="1">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
<unit id="org.eclipse.equinox.p2.discovery.feature.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.rcp.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/releases/luna"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.license.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/cbi/updates/license"/>
</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.swtbot.generator.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/technology/swtbot/releases/latest"/>
+</location>
</locations>
</target>
diff --git a/org.eclipse.epp.mpc-target/maintenance.target b/org.eclipse.epp.mpc-target/maintenance.target index ba8fe6c1..03a917a9 100644 --- a/org.eclipse.epp.mpc-target/maintenance.target +++ b/org.eclipse.epp.mpc-target/maintenance.target @@ -1,19 +1,22 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
-<target name="Maintenance" sequenceNumber="10">
+<target name="MPC Target Platform - Maintenance" sequenceNumber="10">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
<unit id="org.eclipse.equinox.p2.discovery.feature.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.rcp.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/releases/maintenance"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.license.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/cbi/updates/license"/>
</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.swtbot.generator.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/technology/swtbot/releases/latest"/>
+</location>
</locations>
</target>
diff --git a/org.eclipse.epp.mpc-target/staging.target b/org.eclipse.epp.mpc-target/staging.target index 1c57d109..23b598a9 100644 --- a/org.eclipse.epp.mpc-target/staging.target +++ b/org.eclipse.epp.mpc-target/staging.target @@ -1,19 +1,22 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
-<target name="Staging" sequenceNumber="0">
+<target name="MPC Target Platform - Staging" sequenceNumber="0">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
<unit id="org.eclipse.equinox.p2.discovery.feature.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
-<unit id="org.eclipse.rcp.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/releases/staging"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.license.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/cbi/updates/license"/>
</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.swtbot.generator.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/technology/swtbot/releases/latest"/>
+</location>
</locations>
</target>
diff --git a/org.eclipse.epp.mpc.core/.project b/org.eclipse.epp.mpc.core/.project index 59bf97d2..be79398e 100644 --- a/org.eclipse.epp.mpc.core/.project +++ b/org.eclipse.epp.mpc.core/.project @@ -25,6 +25,11 @@ <arguments> </arguments> </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ds.core.builder</name> + <arguments> + </arguments> + </buildCommand> </buildSpec> <natures> <nature>org.eclipse.pde.PluginNature</nature> diff --git a/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF b/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF index e1638eea..435dfdc5 100644 --- a/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF +++ b/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF @@ -9,11 +9,16 @@ Require-Bundle: org.eclipse.osgi;bundle-version="3.6.0", org.eclipse.core.runtime;bundle-version="3.6.0", org.apache.commons.logging;bundle-version="1.0.4", org.eclipse.equinox.p2.repository;bundle-version="2.0.0", - org.eclipse.core.net;bundle-version="1.2.100" + org.eclipse.core.net;bundle-version="1.2.100", + org.eclipse.equinox.ds;bundle-version="1.4.200", + org.eclipse.osgi.services;bundle-version="3.4.0", + org.eclipse.equinox.util;bundle-version="1.0.500" Export-Package: org.eclipse.epp.internal.mpc.core;x-friends:="org.eclipse.epp.mpc.ui", org.eclipse.epp.internal.mpc.core.service;x-friends:="org.eclipse.epp.mpc.ui", org.eclipse.epp.internal.mpc.core.service.xml;x-internal:=true, - org.eclipse.epp.internal.mpc.core.util;x-friends:="org.eclipse.epp.mpc.ui" + org.eclipse.epp.internal.mpc.core.util;x-friends:="org.eclipse.epp.mpc.ui", + org.eclipse.epp.mpc.core.model, + org.eclipse.epp.mpc.core.service Import-Package: org.apache.http;version="4.1.0", org.apache.http.auth;version="4.1.0", org.apache.http.client;version="4.1.0", @@ -27,3 +32,4 @@ Import-Package: org.apache.http;version="4.1.0", org.eclipse.equinox.p2.core;version="2.0.0" Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin +Service-Component: OSGI-INF/services/*.xml diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/service-locator.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/service-locator.xml new file mode 100644 index 00000000..5510b761 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/service-locator.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2014 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 v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ The Eclipse Foundation - initial API and implementation
+ -->
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.core.servicelocator">
+ <implementation class="org.eclipse.epp.internal.mpc.core.ServiceLocator"/>
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator"/>
+ </service>
+</scr:component>
diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/unmarshaller.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/unmarshaller.xml new file mode 100644 index 00000000..afe06578 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/unmarshaller.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2014 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 v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ The Eclipse Foundation - initial API and implementation
+ -->
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.core.unmarshaller">
+ <implementation class="org.eclipse.epp.internal.mpc.core.service.MarketplaceUnmarshaller"/>
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller"/>
+ </service>
+</scr:component>
diff --git a/org.eclipse.epp.mpc.core/build.properties b/org.eclipse.epp.mpc.core/build.properties index ef479b0c..1c6dd1ff 100644 --- a/org.eclipse.epp.mpc.core/build.properties +++ b/org.eclipse.epp.mpc.core/build.properties @@ -1,18 +1,9 @@ -############################################################################### -# Copyright (c) 2010 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 v1.0 -# which accompanies this distribution, and is available at -# http://www.eclipse.org/legal/epl-v10.html -# -# Contributors: -# The Eclipse Foundation - initial API and implementation -############################################################################### -source.. = src/ output.. = bin/ bin.includes = META-INF/,\ .,\ about.html,\ OSGI-INF/,\ - OSGI-INF/l10n/ + OSGI-INF/l10n/,\ + OSGI-INF/services/ src.includes = about.html +source.. = src/ diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/MarketplaceClientCorePlugin.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/MarketplaceClientCorePlugin.java index 30e91b5f..154527c9 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/MarketplaceClientCorePlugin.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/MarketplaceClientCorePlugin.java @@ -7,29 +7,85 @@ * * Contributors: * Yatta Solutions - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + import org.eclipse.epp.internal.mpc.core.util.ProxyHelper; +import org.eclipse.epp.internal.mpc.core.util.TransportFactory; +import org.eclipse.epp.mpc.core.service.ITransportFactory; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; public class MarketplaceClientCorePlugin implements BundleActivator { - private static Bundle bundle; + private static MarketplaceClientCorePlugin instance; + + private Bundle bundle; + + private List<ServiceRegistration<?>> serviceRegistrations; + + private ServiceHelperImpl serviceHelper; public void start(BundleContext context) throws Exception { bundle = context.getBundle(); + instance = this; ProxyHelper.acquireProxyService(); + registerServices(context); + serviceHelper = new ServiceHelperImpl(); + serviceHelper.startTracking(context); } public void stop(BundleContext context) throws Exception { + serviceHelper.stopTracking(context); + serviceHelper = null; + unregisterServices(); ProxyHelper.releaseProxyService(); - bundle = null; + instance = null; + } + + private void registerServices(BundleContext context) { + List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>(); + this.serviceRegistrations = serviceRegistrations; + + List<ITransportFactory> factories = TransportFactory.listAvailableFactories();//highest-prio factory comes first + int prio = 100 * factories.size();//prio counts down from highest value to 0 in steps of 100 + for (ITransportFactory factory : factories) { + prio -= 100; + Hashtable<String, Object> properties = new Hashtable<String, Object>(); + properties.put(Constants.SERVICE_RANKING, prio); + ServiceRegistration<ITransportFactory> registration = context.registerService(ITransportFactory.class, + factory, properties); + serviceRegistrations.add(registration); + } + } + + private void unregisterServices() { + List<ServiceRegistration<?>> serviceRegistrations = this.serviceRegistrations; + this.serviceRegistrations = null; + if (serviceRegistrations != null) { + for (ServiceRegistration<?> serviceRegistration : serviceRegistrations) { + serviceRegistration.unregister(); + } + } + } + + public ServiceHelperImpl getServiceHelper() { + return serviceHelper; + } + + public static MarketplaceClientCorePlugin getDefault() { + return instance; } public static Bundle getBundle() { - return bundle; + return instance == null ? null : instance.bundle; } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceHelperImpl.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceHelperImpl.java new file mode 100644 index 00000000..6397300d --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceHelperImpl.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.core; + +import org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator; +import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller; +import org.eclipse.epp.mpc.core.service.ITransportFactory; +import org.eclipse.epp.mpc.core.service.ServiceHelper; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * @author Carsten Reckord + */ +class ServiceHelperImpl extends ServiceHelper { + + private ServiceTracker<IMarketplaceServiceLocator, IMarketplaceServiceLocator> locatorServiceTracker; + + private ServiceTracker<ITransportFactory, ITransportFactory> transportFactoryTracker; + + private ServiceTracker<IMarketplaceUnmarshaller, IMarketplaceUnmarshaller> unmarshallerTracker; + + void startTracking(BundleContext context) { + locatorServiceTracker = new ServiceTracker<IMarketplaceServiceLocator, IMarketplaceServiceLocator>(context, + IMarketplaceServiceLocator.class, null); + locatorServiceTracker.open(true); + + transportFactoryTracker = new ServiceTracker<ITransportFactory, ITransportFactory>(context, + ITransportFactory.class, null); + transportFactoryTracker.open(true); + + unmarshallerTracker = new ServiceTracker<IMarketplaceUnmarshaller, IMarketplaceUnmarshaller>(context, + IMarketplaceUnmarshaller.class, null); + unmarshallerTracker.open(true); + } + + void stopTracking(BundleContext context) { + if (locatorServiceTracker != null) { + locatorServiceTracker.close(); + locatorServiceTracker = null; + } + if (transportFactoryTracker != null) { + transportFactoryTracker.close(); + transportFactoryTracker = null; + } + if (unmarshallerTracker != null) { + unmarshallerTracker.close(); + unmarshallerTracker = null; + } + } + + @Override + protected IMarketplaceServiceLocator doGetMarketplaceServiceLocator() { + return locatorServiceTracker == null ? null : locatorServiceTracker.getService(); + } + + @Override + protected IMarketplaceUnmarshaller doGetMarketplaceUnmarshaller() { + return unmarshallerTracker == null ? null : unmarshallerTracker.getService(); + } + + @Override + protected ITransportFactory doGetTransportFactory() { + return transportFactoryTracker == null ? null : transportFactoryTracker.getService(); + } +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceLocator.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceLocator.java index 615fb013..89781a84 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceLocator.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/ServiceLocator.java @@ -7,43 +7,261 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core; -import org.eclipse.epp.internal.mpc.core.service.CatalogService; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProduct; +import org.eclipse.core.runtime.Platform; +import org.eclipse.epp.internal.mpc.core.service.CachingMarketplaceService; import org.eclipse.epp.internal.mpc.core.service.DefaultCatalogService; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.MarketplaceService; +import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; +import org.eclipse.epp.mpc.core.service.ICatalogService; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; +import org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator; +import org.eclipse.epp.mpc.core.service.ServiceHelper; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; /** - * A service locator for obtaining {@link MarketplaceService} instances. - * + * A service locator for obtaining {@link IMarketplaceService} instances. + * * @author David Green + * @author Carsten Reckord */ -public class ServiceLocator { +public class ServiceLocator implements IMarketplaceServiceLocator { + + private static ServiceLocator instance; + + private Map<String, IMarketplaceService> marketplaceServices; + + private ICatalogService catalogService; + + private ServiceTracker<IMarketplaceService, IMarketplaceService> marketplaceServiceTracker; + + private ServiceTracker<ICatalogService, ICatalogService> catalogServiceTracker; + + private URL defaultCatalogUrl; - private static ServiceLocator instance = new ServiceLocator(); + private URL defaultMarketplaceUrl; - public MarketplaceService getMarketplaceService() { - return new DefaultMarketplaceService(); + public ServiceLocator() { + defaultMarketplaceUrl = DefaultMarketplaceService.DEFAULT_SERVICE_URL; + defaultCatalogUrl = DefaultCatalogService.DEFAULT_CATALOG_SERVICE_URL; } - public CatalogService getCatalogService() { - return new DefaultCatalogService(); + /** + * @deprecated use {@link #getDefaultMarketplaceService()} or {@link #getMarketplaceService(String)} instead + */ + @Deprecated + public IMarketplaceService getMarketplaceService() { + return getDefaultMarketplaceService(); + } + + public IMarketplaceService getDefaultMarketplaceService() { + return getMarketplaceService(defaultMarketplaceUrl.toExternalForm()); + } + + public synchronized IMarketplaceService getMarketplaceService(String baseUrl) { + IMarketplaceService service; + if (marketplaceServiceTracker != null) { + ServiceReference<IMarketplaceService>[] serviceReferences = marketplaceServiceTracker.getServiceReferences(); + if (serviceReferences != null) { + for (ServiceReference<IMarketplaceService> serviceReference : serviceReferences) { + Object serviceBaseUrl = serviceReference.getProperty(IMarketplaceService.BASE_URL); + if (baseUrl.equals(serviceBaseUrl)) { + service = marketplaceServiceTracker.getService(serviceReference); + //we don't cache this on our own, since it might become invalid + if (service != null) { + return service; + } + } + } + } + } + if (marketplaceServices != null) { + service = marketplaceServices.get(baseUrl); + if (service != null) { + return service; + } + } + service = createMarketplaceService(baseUrl); + + if (marketplaceServices != null) { + marketplaceServices.put(baseUrl, service); + } + return service; + } + + protected IMarketplaceService createMarketplaceService(String baseUrl) { + IMarketplaceService service; + URL base; + try { + base = new URL(baseUrl); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + DefaultMarketplaceService defaultService = new DefaultMarketplaceService(base); + Map<String, String> requestMetaParameters = computeDefaultRequestMetaParameters(); + defaultService.setRequestMetaParameters(requestMetaParameters); + service = new CachingMarketplaceService(defaultService); + return service; + } + + /** + * OSGi service activation method. Activation will cause the locator to start managing individual marketplace + * services and return the same instances per base url on subsequent calls to {@link #getMarketplaceService(String)} + * . + */ + public synchronized void activate(BundleContext context, Map<?, ?> properties) { + URL baseUrl = ServiceUtil.getUrl(properties, DEFAULT_URL, null); + + URL catalogUrl = ServiceUtil.getUrl(properties, CATALOG_URL, baseUrl); + if (catalogUrl != null) { + this.defaultCatalogUrl = catalogUrl; + } //else the default value from the constructor is used + + URL marketplaceUrl = ServiceUtil.getUrl(properties, DEFAULT_MARKETPLACE_URL, baseUrl); + if (marketplaceUrl != null) { + this.defaultMarketplaceUrl = marketplaceUrl; + } //else the default value from the constructor is used + + if (marketplaceServices == null) { + marketplaceServices = new HashMap<String, IMarketplaceService>(); + } + + marketplaceServiceTracker = new ServiceTracker<IMarketplaceService, IMarketplaceService>(context, + IMarketplaceService.class, null); + marketplaceServiceTracker.open(true); + + catalogServiceTracker = new ServiceTracker<ICatalogService, ICatalogService>(context, + ICatalogService.class, null); + catalogServiceTracker.open(true); + } + + /** + * OSGi service activation method. Deactivation will cause the locator to stop managing individual marketplace + * services. Multiple calls to {@link #getMarketplaceService(String)} will return a new instance every time. + */ + public synchronized void deactivate() { + if (marketplaceServiceTracker != null) { + marketplaceServiceTracker.close(); + marketplaceServiceTracker = null; + } + if (catalogServiceTracker != null) { + catalogServiceTracker.close(); + catalogServiceTracker = null; + } + marketplaceServices = null; + catalogService = null; + } + + public synchronized ICatalogService getCatalogService() { + if (catalogServiceTracker != null) { + ICatalogService registeredService = catalogServiceTracker.getService(); + if (registeredService != null) { + //we don't cache this on our own, since it might become invalid + return registeredService; + } + } + if (catalogService != null) { + return catalogService; + } + ICatalogService catalogService = new DefaultCatalogService(defaultCatalogUrl); + if (marketplaceServices != null) {//used as an indicator to cache value + this.catalogService = catalogService; + } + return catalogService; } /** * for testing purposes + * + * @deprecated don't call this outside of tests */ + @Deprecated public static synchronized void setInstance(ServiceLocator instance) { - if (instance == null) { - throw new IllegalArgumentException(); - } ServiceLocator.instance = instance; } + /** + * @deprecated acquire the registered {@link IMarketplaceServiceLocator} OSGi service instead. + */ + @Deprecated public static synchronized ServiceLocator getInstance() { + if (instance != null) { + return instance; + } + IMarketplaceServiceLocator locator = getCompatibilityLocator(); + if (locator != null) { + if (locator instanceof ServiceLocator) { + //don't remember service instance, it might get deregistered + return (ServiceLocator) locator; + } + } + //remember new default instance + instance = new ServiceLocator(); return instance; } + /** + * This method is not intended to be referenced by clients. Acquire the registered + * {@link IMarketplaceServiceLocator} OSGi service instead. + * <p> + * This method provides legacy compatibility with the ServiceLocator singleton for internal use only. It will return + * the ServiceLocator singleton if it has been set explicitly. Otherwise it will return the registered default + * {@link IMarketplaceServiceLocator} OSGi service. + * + * @noreference This method is not intended to be referenced by clients. + */ + public static synchronized IMarketplaceServiceLocator getCompatibilityLocator() { + if (instance != null) { + return instance; + } + IMarketplaceServiceLocator locator = ServiceHelper.getMarketplaceServiceLocator(); + if (locator == null) { + //remember new default instance + instance = new ServiceLocator(); + locator = instance; + } + return locator; + } + + public static Map<String, String> computeDefaultRequestMetaParameters() { + Map<String, String> requestMetaParameters = new HashMap<String, String>(); + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_CLIENT, MarketplaceClientCore.BUNDLE_ID); + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_OS, Platform.getOS()); + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_WS, Platform.getWS()); + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_NL, Platform.getNL()); + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_JAVA_VERSION, System.getProperty("java.version")); //$NON-NLS-1$ + IProduct product = Platform.getProduct(); + if (product != null) { + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PRODUCT, product.getId()); + Bundle productBundle = product.getDefiningBundle(); + if (productBundle != null) { + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION, + productBundle.getVersion().toString()); + } + } + Bundle runtimeBundle = Platform.getBundle("org.eclipse.core.runtime"); //$NON-NLS-1$ + if (runtimeBundle != null) { + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION, runtimeBundle.getVersion() + .toString()); + } + // also send the platform version to distinguish between 3.x and 4.x platforms using the same runtime + Bundle platformBundle = Platform.getBundle("org.eclipse.platform"); //$NON-NLS-1$ + if (platformBundle != null) { + requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION, + platformBundle.getVersion().toString()); + } + return requestMetaParameters; + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CachingMarketplaceService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CachingMarketplaceService.java index 5096f5cd..d35839aa 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CachingMarketplaceService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CachingMarketplaceService.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; @@ -20,10 +21,16 @@ import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.epp.mpc.core.model.ICategory; +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; -public class CachingMarketplaceService implements MarketplaceService { +public class CachingMarketplaceService implements IMarketplaceService { - private final MarketplaceService delegate; + private final IMarketplaceService delegate; private int maxCacheSize = 30; @@ -36,7 +43,7 @@ public class CachingMarketplaceService implements MarketplaceService { } }; - public CachingMarketplaceService(MarketplaceService delegate) { + public CachingMarketplaceService(IMarketplaceService delegate) { if (delegate == null) { throw new IllegalArgumentException(); } @@ -51,21 +58,21 @@ public class CachingMarketplaceService implements MarketplaceService { this.maxCacheSize = maxCacheSize; } - public List<Market> listMarkets(IProgressMonitor monitor) throws CoreException { + public List<? extends IMarket> listMarkets(IProgressMonitor monitor) throws CoreException { return delegate.listMarkets(monitor); } - public Market getMarket(Market market, IProgressMonitor monitor) throws CoreException { + public IMarket getMarket(IMarket market, IProgressMonitor monitor) throws CoreException { return delegate.getMarket(market, monitor); } - public Category getCategory(Category category, IProgressMonitor monitor) throws CoreException { + public ICategory getCategory(ICategory category, IProgressMonitor monitor) throws CoreException { return delegate.getCategory(category, monitor); } - public Node getNode(Node node, IProgressMonitor monitor) throws CoreException { + public INode getNode(INode node, IProgressMonitor monitor) throws CoreException { String nodeKey = computeNodeKey(node); - Node nodeResult = null; + INode nodeResult = null; if (nodeKey != null) { synchronized (cache) { Reference<Object> reference = cache.get(nodeKey); @@ -85,7 +92,7 @@ public class CachingMarketplaceService implements MarketplaceService { return nodeResult; } - private String computeNodeKey(Node node) { + private String computeNodeKey(INode node) { if (node.getId() != null) { return "Node:" + node.getId(); //$NON-NLS-1$ } @@ -93,27 +100,27 @@ public class CachingMarketplaceService implements MarketplaceService { } private interface SearchOperation { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException; + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException; } - public SearchResult search(final Market market, final Category category, final String queryText, + public ISearchResult search(final IMarket market, final ICategory category, final String queryText, IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("search", market, category, queryText); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { return delegate.search(market, category, queryText, monitor); } }); } - private SearchResult performSearch(IProgressMonitor monitor, String key, SearchOperation searchOperation) + private ISearchResult performSearch(IProgressMonitor monitor, String key, SearchOperation searchOperation) throws CoreException { - SearchResult result = null; + ISearchResult result = null; synchronized (cache) { Reference<Object> reference = cache.get(key); if (reference != null) { - result = (SearchResult) reference.get(); + result = (ISearchResult) reference.get(); } } if (result == null) { @@ -121,7 +128,7 @@ public class CachingMarketplaceService implements MarketplaceService { if (result != null) { synchronized (cache) { cache.put(key, new SoftReference<Object>(result)); - for (Node node : result.getNodes()) { + for (INode node : result.getNodes()) { cache.put(computeNodeKey(node), new SoftReference<Object>(node)); } } @@ -130,69 +137,78 @@ public class CachingMarketplaceService implements MarketplaceService { return result; } - private String computeSearchKey(String prefix, Market market, Category category, String queryText) { + private String computeSearchKey(String prefix, IMarket market, ICategory category, String queryText) { return prefix + ":" + (market == null ? "" : market.getId()) + ":" + (category == null ? "" : category.getId()) + ":" + (queryText == null ? "" : queryText.trim()); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$ //$NON-NLS-6$ } - public SearchResult featured(IProgressMonitor monitor) throws CoreException { + public ISearchResult featured(IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("featured", null, null, null); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { return delegate.featured(monitor); } }); } - public SearchResult featured(IProgressMonitor monitor, final Market market, final Category category) + public ISearchResult featured(final IMarket market, final ICategory category, IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("featured", market, category, null); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { - return delegate.featured(monitor, market, category); + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { + return delegate.featured(market, category, monitor); } }); } - public SearchResult recent(IProgressMonitor monitor) throws CoreException { + public ISearchResult recent(IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("recent", null, null, null); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { return delegate.recent(monitor); } }); } - public SearchResult favorites(IProgressMonitor monitor) throws CoreException { + public ISearchResult favorites(IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("favorites", null, null, null); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { return delegate.favorites(monitor); } }); } - public SearchResult popular(IProgressMonitor monitor) throws CoreException { + public ISearchResult popular(IProgressMonitor monitor) throws CoreException { String key = computeSearchKey("popular", null, null, null); //$NON-NLS-1$ return performSearch(monitor, key, new SearchOperation() { - public SearchResult doSearch(IProgressMonitor monitor) throws CoreException { + public ISearchResult doSearch(IProgressMonitor monitor) throws CoreException { return delegate.popular(monitor); } }); } - public News news(IProgressMonitor monitor) throws CoreException { + public INews news(IProgressMonitor monitor) throws CoreException { return delegate.news(monitor); } public void reportInstallError(IProgressMonitor monitor, IStatus result, Set<Node> nodes, Set<String> iuIdsAndVersions, String resolutionDetails) throws CoreException { - delegate.reportInstallError(monitor, result, nodes, iuIdsAndVersions, resolutionDetails); + reportInstallError(result, nodes, iuIdsAndVersions, resolutionDetails, monitor); + } + + public void reportInstallError(IStatus result, Set<? extends INode> nodes, Set<String> iuIdsAndVersions, + String resolutionDetails, IProgressMonitor monitor) throws CoreException { + delegate.reportInstallError(result, nodes, iuIdsAndVersions, resolutionDetails, monitor); + } + + public void reportInstallSuccess(INode node, IProgressMonitor monitor) { + delegate.reportInstallSuccess(node, monitor); } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalog.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalog.java index dab50ffc..44722e71 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalog.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalog.java @@ -4,17 +4,20 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ICatalog; + /** * @author Benjamin Muskalla */ -public class Catalog extends Identifiable { +public class Catalog extends Identifiable implements ICatalog { private boolean selfContained; @@ -78,4 +81,9 @@ public class Catalog extends Identifiable { public void setNews(News news) { this.news = news; } + + @Override + protected boolean equalsType(Object obj) { + return obj instanceof ICatalog; + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java index bdb7ebfb..26d22129 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogBranding.java @@ -4,17 +4,20 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ICatalogBranding; + /** * @author Benjamin Muskalla */ -public class CatalogBranding extends Identifiable { +public class CatalogBranding extends Identifiable implements ICatalogBranding { private String wizardIcon; @@ -96,4 +99,8 @@ public class CatalogBranding extends Identifiable { this.wizardTitle = wizardTitle; } + @Override + protected boolean equalsType(Object obj) { + return obj instanceof ICatalogBranding; + } }
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogService.java index 3f2d0e88..fa488dc4 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/CatalogService.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; @@ -14,8 +15,13 @@ import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.epp.mpc.core.service.ICatalogService; -public interface CatalogService { +/** + * @deprecated Use {@link org.eclipse.epp.mpc.core.service.ICatalogService} instead. + */ +@Deprecated +public interface CatalogService extends ICatalogService { public List<Catalog> listCatalogs(IProgressMonitor monitor) throws CoreException; diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalogs.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalogs.java index 0a9e8c07..1f1ba23f 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalogs.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Catalogs.java @@ -4,16 +4,19 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ICatalogs; + /** * @author Benjamin Muskalla */ -public class Catalogs { +public class Catalogs implements ICatalogs { protected java.util.List<Catalog> catalogs = new java.util.ArrayList<Catalog>(); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Categories.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Categories.java index 64c9f09d..f7461def 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Categories.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Categories.java @@ -7,14 +7,17 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ICategories; + /** * @author David Green */ -public class Categories { +public class Categories implements ICategories { protected java.util.List<Category> category = new java.util.ArrayList<Category>(); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Category.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Category.java index 42012487..0fadf19a 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Category.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Category.java @@ -4,38 +4,45 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ICategory; + /** * @author David Green */ -public class Category extends Identifiable { - +public class Category extends Identifiable implements ICategory { + protected Integer count; protected java.util.List<Node> node = new java.util.ArrayList<Node>(); - + public Category() { } - + public Integer getCount() { return count; } - + public void setCount(Integer count) { this.count = count; } - + public java.util.List<Node> getNode() { return node; } - + public void setNode(java.util.List<Node> node) { this.node = node; } - + + @Override + protected boolean equalsType(Object obj) { + return obj instanceof Category; + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultCatalogService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultCatalogService.java index e57d8679..3343cdaa 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultCatalogService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultCatalogService.java @@ -7,32 +7,39 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; -import java.net.MalformedURLException; import java.net.URL; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; +import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.eclipse.epp.mpc.core.service.ICatalogService; -public class DefaultCatalogService extends RemoteMarketplaceService<Catalogs> implements CatalogService { +public class DefaultCatalogService extends RemoteMarketplaceService<Catalogs> implements ICatalogService { public static final String DEFAULT_CATALOG_SERVICE_LOCATION = System.getProperty(DefaultCatalogService.class.getName() + ".url", "http://marketplace.eclipse.org"); //$NON-NLS-1$//$NON-NLS-2$ + public static final URL DEFAULT_CATALOG_SERVICE_URL; + + static { + DEFAULT_CATALOG_SERVICE_URL = ServiceUtil.parseUrl(DEFAULT_CATALOG_SERVICE_LOCATION); + } + public DefaultCatalogService() { - try { - baseUrl = new URL(DEFAULT_CATALOG_SERVICE_LOCATION); - } catch (MalformedURLException e) { - MarketplaceClientCore.error(e); - baseUrl = null; - } + this(null); + } + + public DefaultCatalogService(URL baseUrl) { + this.baseUrl = baseUrl == null ? DEFAULT_CATALOG_SERVICE_URL : baseUrl; } - public List<Catalog> listCatalogs(IProgressMonitor monitor) throws CoreException { + public List<? extends ICatalog> listCatalogs(IProgressMonitor monitor) throws CoreException { Catalogs result = processRequest("catalogs/" + API_URI_SUFFIX, monitor); //$NON-NLS-1$ return result.getCatalogs(); } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultMarketplaceService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultMarketplaceService.java index 09ad4ae1..0a6cc1f7 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultMarketplaceService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/DefaultMarketplaceService.java @@ -7,17 +7,17 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - bug 397004, bug 385936 + * Yatta Solutions - bug 397004, bug 385936, bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.io.InputStream; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -31,15 +31,24 @@ import org.apache.http.message.BasicNameValuePair; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.epp.internal.mpc.core.util.HttpUtil; +import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IIdentifiable; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; import org.eclipse.osgi.util.NLS; /** * @author David Green * @author Carsten Reckord */ -public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketplace> implements MarketplaceService { +@SuppressWarnings("deprecation") +public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketplace> implements IMarketplaceService, +MarketplaceService { // This provisional API will be identified by /api/p at the end of most urls. // @@ -81,44 +90,46 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl public static final String DEFAULT_SERVICE_LOCATION = System.getProperty(MarketplaceService.class.getName() + ".url", "http://marketplace.eclipse.org"); //$NON-NLS-1$//$NON-NLS-2$ + public static final URL DEFAULT_SERVICE_URL; + /** * parameter identifying client - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_CLIENT = "client"; //$NON-NLS-1$ /** * parameter identifying windowing system as reported by {@link org.eclipse.core.runtime.Platform#getWS()} - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_WS = "ws"; //$NON-NLS-1$ /** * parameter identifying operating system as reported by {@link org.eclipse.core.runtime.Platform#getOS()} - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_OS = "os"; //$NON-NLS-1$ /** * parameter identifying the current local as reported by {@link org.eclipse.core.runtime.Platform#getNL()} - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_NL = "nl"; //$NON-NLS-1$ /** * parameter identifying Java version - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_JAVA_VERSION = "java.version"; //$NON-NLS-1$ /** * parameter identifying the Eclipse runtime version (the version of the org.eclipse.core.runtime bundle) - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_RUNTIME_VERSION = "runtime.version"; //$NON-NLS-1$ @@ -127,36 +138,35 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl * parameter identifying the Eclipse platform version (the version of the org.eclipse.platform bundle) This * parameter is optional and only sent if the platform bundle is present. It is used to identify the actual running * platform's version (esp. where different platforms share the same runtime, like the parallel 3.x/4.x versions) - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_PLATFORM_VERSION = "platform.version"; //$NON-NLS-1$ /** * parameter identifying the Eclipse product version - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_PRODUCT_VERSION = "product.version"; //$NON-NLS-1$ /** * parameter identifying the product id, as provided by <code>Platform.getProduct().getId()</code> - * + * * @see {@link #setRequestMetaParameters(Map)} */ public static final String META_PARAM_PRODUCT = "product"; //$NON-NLS-1$ + static { + DEFAULT_SERVICE_URL = ServiceUtil.parseUrl(DEFAULT_SERVICE_LOCATION); + } + public DefaultMarketplaceService(URL baseUrl) { - this.baseUrl = baseUrl; + this.baseUrl = baseUrl == null ? DEFAULT_SERVICE_URL : baseUrl; } public DefaultMarketplaceService() { - try { - baseUrl = new URL(DEFAULT_SERVICE_LOCATION); - } catch (MalformedURLException e) { - MarketplaceClientCore.error(e); - baseUrl = null; - } + this(null); } public List<Market> listMarkets(IProgressMonitor monitor) throws CoreException { @@ -164,17 +174,55 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl return marketplace.getMarket(); } - public Market getMarket(Market market, IProgressMonitor monitor) throws CoreException { - Marketplace marketplace = processRequest(market.getUrl(), API_URI_SUFFIX, monitor); - if (marketplace.getMarket().isEmpty()) { - throw new CoreException(createErrorStatus(Messages.DefaultMarketplaceService_marketNotFound, null)); - } else if (marketplace.getMarket().size() > 1) { - throw new CoreException(createErrorStatus(Messages.DefaultMarketplaceService_unexpectedResponse, null)); + public Market getMarket(IMarket market, IProgressMonitor monitor) throws CoreException { + if (market.getId() == null && market.getUrl() != null) { + throw new IllegalArgumentException(); + } + List<Market> markets = listMarkets(monitor); + if (market.getId() != null) { + String marketId = market.getId(); + for (Market aMarket : markets) { + if (marketId.equals(aMarket.getId())) { + return aMarket; + } + } + } else if (market.getUrl() != null) { + String marketUrl = market.getUrl(); + for (Market aMarket : markets) { + if (marketUrl.equals(aMarket.getUrl())) { + return aMarket; + } + } } - return marketplace.getMarket().get(0); + throw new CoreException(createErrorStatus(Messages.DefaultMarketplaceService_marketNotFound, null)); } - public Category getCategory(Category category, IProgressMonitor monitor) throws CoreException { + public Market getMarket(Market market, IProgressMonitor monitor) throws CoreException { + return getMarket((IMarket) market, monitor); + } + + public Category getCategory(ICategory category, IProgressMonitor monitor) throws CoreException { + if (category.getId() != null && category.getUrl() == null) { + SubMonitor progress = SubMonitor.convert(monitor, 100); + List<Market> markets = listMarkets(progress.newChild(50)); + ICategory resolvedCategory = null; + outer: for (Market market : markets) { + List<Category> categories = market.getCategory(); + for (Category aCategory : categories) { + if (aCategory.equalsId(category)) { + resolvedCategory = aCategory; + break outer; + } + } + } + if (progress.isCanceled()) { + throw new OperationCanceledException(); + } else if (resolvedCategory == null) { + throw new CoreException(createErrorStatus(Messages.DefaultMarketplaceService_categoryNotFound, null)); + } else { + return getCategory(resolvedCategory, progress.newChild(50)); + } + } Marketplace marketplace = processRequest(category.getUrl(), API_URI_SUFFIX, monitor); if (marketplace.getCategory().isEmpty()) { throw new CoreException(createErrorStatus(Messages.DefaultMarketplaceService_categoryNotFound, null)); @@ -184,18 +232,16 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl return marketplace.getCategory().get(0); } - public Node getNode(Node node, IProgressMonitor monitor) throws CoreException { + public Category getCategory(Category category, IProgressMonitor monitor) throws CoreException { + return getCategory((ICategory) category, monitor); + } + + public Node getNode(INode node, IProgressMonitor monitor) throws CoreException { Marketplace marketplace; if (node.getId() != null) { // bug 304928: prefer the id method rather than the URL, since the id provides a stable URL and the // URL is based on the name, which could change. - String encodedId; - try { - encodedId = URLEncoder.encode(node.getId(), UTF_8); - } catch (UnsupportedEncodingException e) { - // should never happen - throw new IllegalStateException(e); - } + String encodedId = urlEncode(node.getId()); marketplace = processRequest(API_NODE_URI + '/' + encodedId + '/' + API_URI_SUFFIX, monitor); } else { marketplace = processRequest(node.getUrl(), API_URI_SUFFIX, monitor); @@ -208,7 +254,11 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl return marketplace.getNode().get(0); } - public SearchResult search(Market market, Category category, String queryText, IProgressMonitor monitor) + public Node getNode(Node node, IProgressMonitor monitor) throws CoreException { + return getNode((INode) node, monitor); + } + + public SearchResult search(IMarket market, ICategory category, String queryText, IProgressMonitor monitor) throws CoreException { SearchResult result = new SearchResult(); String relativeUrl = computeRelativeSearchUrl(market, category, queryText, true); @@ -238,6 +288,11 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl return result; } + public SearchResult search(Market market, Category category, String queryText, IProgressMonitor monitor) + throws CoreException { + return search((IMarket) market, (ICategory) category, queryText, monitor); + } + /** * Creates the query URL for the Marketplace REST API. * <p> @@ -251,7 +306,7 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl * order. * <p> * If the query is empty and both category and market are null, the result is null - * + * * @param market * the market to search or null * @param category @@ -264,71 +319,63 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl * <code>api/p/search/apachesolr_search/WikiText?filters=tid:38%20tid:31</code> or * <code>taxonomy/term/38,31/api/p</code> */ - public String computeRelativeSearchUrl(Market market, Category category, String queryText, boolean api) { + public String computeRelativeSearchUrl(IMarket market, ICategory category, String queryText, boolean api) { String relativeUrl; - try { - if (queryText != null && queryText.trim().length() > 0) { - relativeUrl = (api ? API_SEARCH_URI_FULL : API_SEARCH_URI) + URLEncoder.encode(queryText.trim(), UTF_8); - String queryString = ""; //$NON-NLS-1$ - if (market != null || category != null) { - queryString += "filters="; //$NON-NLS-1$ - Identifiable first = api ? market : category; - Identifiable second = api ? category : market; - if (first != null) { - queryString += "tid:" + URLEncoder.encode(first.getId(), UTF_8); //$NON-NLS-1$ - if (second != null) { - queryString += "%20"; //$NON-NLS-1$ - } - } + if (queryText != null && queryText.trim().length() > 0) { + relativeUrl = (api ? API_SEARCH_URI_FULL : API_SEARCH_URI) + urlEncode(queryText.trim()); + String queryString = ""; //$NON-NLS-1$ + if (market != null || category != null) { + queryString += "filters="; //$NON-NLS-1$ + IIdentifiable first = api ? market : category; + IIdentifiable second = api ? category : market; + if (first != null) { + queryString += "tid:" + urlEncode(first.getId()); //$NON-NLS-1$ if (second != null) { - queryString += "tid:" + URLEncoder.encode(second.getId(), UTF_8); //$NON-NLS-1$ + queryString += "%20"; //$NON-NLS-1$ } } - if (queryString.length() > 0) { - relativeUrl += '?' + queryString; - } - } else if (market != null || category != null) { - // http://marketplace.eclipse.org/taxonomy/term/38,31 - relativeUrl = API_TAXONOMY_URI; - if (category != null) { - relativeUrl += URLEncoder.encode(category.getId(), UTF_8); - if (market != null) { - relativeUrl += ','; - } + if (second != null) { + queryString += "tid:" + urlEncode(second.getId()); //$NON-NLS-1$ } + } + if (queryString.length() > 0) { + relativeUrl += '?' + queryString; + } + } else if (market != null || category != null) { + // http://marketplace.eclipse.org/taxonomy/term/38,31 + relativeUrl = API_TAXONOMY_URI; + if (category != null) { + relativeUrl += urlEncode(category.getId()); if (market != null) { - relativeUrl += URLEncoder.encode(market.getId(), UTF_8); - } - if (api) { - relativeUrl += '/' + API_URI_SUFFIX; + relativeUrl += ','; } - } else { - relativeUrl = null; } - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(e); + if (market != null) { + relativeUrl += urlEncode(market.getId()); + } + if (api) { + relativeUrl += '/' + API_URI_SUFFIX; + } + } else { + relativeUrl = null; } return relativeUrl; } public SearchResult featured(IProgressMonitor monitor) throws CoreException { - return featured(monitor, null, null); + return featured(null, null, monitor); } - public SearchResult featured(IProgressMonitor monitor, Market market, Category category) throws CoreException { + public SearchResult featured(IMarket market, ICategory category, IProgressMonitor monitor) throws CoreException { String nodePart = ""; //$NON-NLS-1$ - try { - if (market != null) { - nodePart += URLEncoder.encode(market.getId(), UTF_8); - } - if (category != null) { - if (nodePart.length() > 0) { - nodePart += ","; //$NON-NLS-1$ - } - nodePart += URLEncoder.encode(category.getId(), UTF_8); + if (market != null) { + nodePart += urlEncode(market.getId()); + } + if (category != null) { + if (nodePart.length() > 0) { + nodePart += ","; //$NON-NLS-1$ } - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(); + nodePart += urlEncode(category.getId()); } String uri = API_FEATURED_URI + '/'; if (nodePart.length() > 0) { @@ -338,6 +385,10 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl return createSearchResult(marketplace.getFeatured()); } + public SearchResult featured(IProgressMonitor monitor, Market market, Category category) throws CoreException { + return featured(market, category, monitor); + } + public SearchResult recent(IProgressMonitor monitor) throws CoreException { Marketplace marketplace = processRequest(API_RECENT_URI + '/' + API_URI_SUFFIX, monitor); return createSearchResult(marketplace.getRecent()); @@ -377,8 +428,17 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl } } + /** + * @deprecated use {@link #reportInstallError(IStatus, Set, Set, String, IProgressMonitor)} instead + */ + @Deprecated public void reportInstallError(IProgressMonitor monitor, IStatus result, Set<Node> nodes, Set<String> iuIdsAndVersions, String resolutionDetails) throws CoreException { + reportInstallError(result, nodes, iuIdsAndVersions, resolutionDetails, monitor); + } + + public void reportInstallError(IStatus result, Set<? extends INode> nodes, Set<String> iuIdsAndVersions, + String resolutionDetails, IProgressMonitor monitor) throws CoreException { HttpClient client; URL location; HttpPost method; @@ -404,7 +464,7 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl parameters.add(new BasicNameValuePair("status", Integer.toString(result.getSeverity()))); //$NON-NLS-1$ parameters.add(new BasicNameValuePair("statusMessage", result.getMessage())); //$NON-NLS-1$ - for (Node node : nodes) { + for (INode node : nodes) { parameters.add(new BasicNameValuePair("node", node.getId())); //$NON-NLS-1$ } if (iuIdsAndVersions != null && !iuIdsAndVersions.isEmpty()) { @@ -427,4 +487,25 @@ public class DefaultMarketplaceService extends RemoteMarketplaceService<Marketpl } } + public void reportInstallSuccess(INode node, IProgressMonitor monitor) { + String url = node.getUrl(); + if (!url.endsWith("/")) { //$NON-NLS-1$ + url += "/"; //$NON-NLS-1$ + } + url += "success"; //$NON-NLS-1$ + url = addMetaParameters(url); + try { + InputStream stream = transport.stream(new URI(url), monitor); + + try { + while (stream.read() != -1) { + // nothing to do + } + } finally { + stream.close(); + } + } catch (Throwable e) { + //per bug 314028 logging this error is not useful. + } + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Identifiable.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Identifiable.java index 45501111..da974aba 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Identifiable.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Identifiable.java @@ -4,18 +4,21 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.IIdentifiable; + /** * @author David Green * @author Carsten Reckord */ -public abstract class Identifiable { +public abstract class Identifiable implements IIdentifiable { protected String id; protected String name; @@ -50,7 +53,7 @@ public abstract class Identifiable { /** * Check if the given object's type and id match. - * + * * @param obj * the object to compare (can be null) * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getId() id} as this object @@ -62,17 +65,85 @@ public abstract class Identifiable { if (obj == null) { return false; } - if (getClass() != obj.getClass()) { + if (!equalsType(obj)) { return false; } - Identifiable other = (Identifiable) obj; + IIdentifiable other = (IIdentifiable) obj; if (id == null) { - if (other.id != null) { + if (other.getId() != null) { + return false; + } + } else if (!id.equals(other.getId())) { + return false; + } + return true; + } + + /** + * Check if the given object's type and url match. + * + * @param obj + * the object to compare (can be null) + * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getUrl() url} as this object + */ + public boolean equalsUrl(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!equalsType(obj)) { + return false; + } + IIdentifiable other = (IIdentifiable) obj; + if (url == null) { + if (other.getUrl() != null) { + return false; + } + } else if (!url.equals(other.getUrl())) { + return false; + } + return true; + } + + /** + * Check if the given object's type and url match. + * + * @param obj + * the object to compare (can be null) + * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getUrl() url} as this object + */ + public boolean equalsName(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!equalsType(obj)) { + return false; + } + IIdentifiable other = (IIdentifiable) obj; + if (name == null) { + if (other.getName() != null) { return false; } - } else if (!id.equals(other.id)) { + } else if (!name.equals(other.getName())) { + return false; + } + return true; + } + + protected boolean equalsType(Object obj) { + if (getClass() != obj.getClass()) { return false; } return true; } + + public static boolean matches(IIdentifiable id1, IIdentifiable id2) { + return id2 == id1 || id2.equalsId(id1) || (id2.getId() == null && id2.equalsUrl(id1)) + || (id2.getId() == null && id2.getUrl() == null && id2.equalsName(id1)); + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Ius.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Ius.java index 53bc5a21..f8e97404 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Ius.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Ius.java @@ -7,14 +7,17 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.IIus; + /** * @author David Green */ -public class Ius { +public class Ius implements IIus { protected java.util.List<String> iu = new java.util.ArrayList<String>(); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Market.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Market.java index 049b279e..b997d4fe 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Market.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Market.java @@ -4,29 +4,37 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.IMarket; + /** * @author David Green */ -public class Market extends Identifiable { - +public class Market extends Identifiable implements IMarket { + protected java.util.List<Category> category = new java.util.ArrayList<Category>(); - + public Market() { } - + public java.util.List<Category> getCategory() { return category; } - + public void setCategory(java.util.List<Category> category) { this.category = category; } - + + @Override + protected boolean equalsType(Object obj) { + return obj instanceof IMarket; + } + } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceService.java index c169d98a..703ad86b 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceService.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; @@ -21,7 +22,9 @@ import org.eclipse.core.runtime.IStatus; * a service that provides access to the marketplace. * * @author David Green + * @deprecated use {@link org.eclipse.epp.mpc.core.service.IMarketplaceService} */ +@Deprecated public interface MarketplaceService { /** diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceUnmarshaller.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceUnmarshaller.java new file mode 100644 index 00000000..18952a8f --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/MarketplaceUnmarshaller.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.core.service; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +import javax.xml.parsers.SAXParserFactory; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; +import org.eclipse.epp.internal.mpc.core.service.xml.Unmarshaller; +import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller; +import org.eclipse.epp.mpc.core.service.UnmarshalException; +import org.eclipse.osgi.util.NLS; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * @author Carsten Reckord + */ +public class MarketplaceUnmarshaller implements IMarketplaceUnmarshaller { + + public <T> T unmarshal(InputStream in, Class<T> type, IProgressMonitor monitor) throws IOException, + UnmarshalException { + final Unmarshaller unmarshaller = new Unmarshaller(); + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + final XMLReader xmlReader; + try { + xmlReader = parserFactory.newSAXParser().getXMLReader(); + } catch (Exception e1) { + throw new IllegalStateException(e1); + } + xmlReader.setContentHandler(unmarshaller); + + // FIXME how can the charset be determined? + Reader reader = new InputStreamReader(new BufferedInputStream(in), RemoteMarketplaceService.UTF_8); + try { + xmlReader.parse(new InputSource(reader)); + } catch (final SAXException e) { + throw new UnmarshalException(createErrorStatus(e.getMessage(), null)); + } + + Object model = unmarshaller.getModel(); + if (model == null) { + // if we reach here this should never happen + throw new IllegalStateException(); + } else { + try { + return type.cast(model); + } catch (Exception e) { + String message = NLS.bind(Messages.DefaultMarketplaceService_unexpectedResponseContent, + model.getClass().getSimpleName()); + throw new UnmarshalException(createErrorStatus(message, null)); + } + } + } + + protected IStatus createErrorStatus(String message, Throwable t) { + return new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID, 0, message, t); + } + +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/News.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/News.java index ba8b5e26..8b410873 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/News.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/News.java @@ -7,13 +7,16 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.INews; + /** * @author Carsten Reckord */ -public class News { +public class News implements INews { private String url; diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Node.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Node.java index 4900796f..a266462f 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Node.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Node.java @@ -4,17 +4,20 @@ * 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: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.INode; + /** * @author David Green * @author Benjamin Muskalla */ -public class Node extends Identifiable { +public class Node extends Identifiable implements INode { protected Integer favorited; protected Integer installsTotal; @@ -264,4 +267,8 @@ public class Node extends Identifiable { this.platforms = platforms; } + @Override + protected boolean equalsType(Object obj) { + return obj instanceof INode; + } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/NotFoundException.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/NotFoundException.java index 4ccd2b4a..1c5dec7b 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/NotFoundException.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/NotFoundException.java @@ -7,12 +7,15 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; /** * @author David Green + * @deprecated unused, will be removed in a future version */ +@Deprecated @SuppressWarnings("serial") public class NotFoundException extends Exception { diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Platforms.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Platforms.java index 282e93fd..01ae8464 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Platforms.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Platforms.java @@ -7,14 +7,17 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.IPlatforms; + /** * @author David Green */ -public class Platforms { +public class Platforms implements IPlatforms { protected java.util.List<String> platform = new java.util.ArrayList<String>(); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/RemoteMarketplaceService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/RemoteMarketplaceService.java index 8e26c240..e57e03d4 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/RemoteMarketplaceService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/RemoteMarketplaceService.java @@ -7,14 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; -import java.io.BufferedInputStream; -import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; @@ -22,21 +19,20 @@ import java.net.URL; import java.net.URLEncoder; import java.util.Map; -import javax.xml.parsers.SAXParserFactory; - import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; -import org.eclipse.epp.internal.mpc.core.service.xml.Unmarshaller; -import org.eclipse.epp.internal.mpc.core.util.ITransport; +import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; import org.eclipse.epp.internal.mpc.core.util.TransportFactory; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; +import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller; +import org.eclipse.epp.mpc.core.service.ITransport; +import org.eclipse.epp.mpc.core.service.ServiceHelper; +import org.eclipse.epp.mpc.core.service.UnmarshalException; import org.eclipse.osgi.util.NLS; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; public class RemoteMarketplaceService<T> { @@ -46,10 +42,22 @@ public class RemoteMarketplaceService<T> { protected static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ - private final ITransport transport = TransportFactory.instance().getTransport(); + protected final ITransport transport; + + protected final IMarketplaceUnmarshaller unmarshaller; private Map<String, String> requestMetaParameters; + public RemoteMarketplaceService() { + this.transport = TransportFactory.createTransport(); + IMarketplaceUnmarshaller unmarshaller = ServiceHelper.getMarketplaceUnmarshaller(); + if (unmarshaller == null) { + //no unmarshaller registered, create a default instance + unmarshaller = new MarketplaceUnmarshaller(); + } + this.unmarshaller = unmarshaller; + } + protected IStatus createErrorStatus(String message, Throwable t) { return new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID, 0, message, t); } @@ -115,38 +123,23 @@ public class RemoteMarketplaceService<T> { throw new CoreException(createErrorStatus(message, e)); } - final Unmarshaller unmarshaller = new Unmarshaller(); monitor.beginTask(NLS.bind(Messages.DefaultMarketplaceService_retrievingDataFrom, baseUri), 100); try { - SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - parserFactory.setNamespaceAware(true); - final XMLReader xmlReader; - try { - xmlReader = parserFactory.newSAXParser().getXMLReader(); - } catch (Exception e1) { - throw new IllegalStateException(e1); - } - xmlReader.setContentHandler(unmarshaller); - InputStream in = transport.stream(location, monitor); try { monitor.worked(30); - // FIXME how can the charset be determined? - Reader reader = new InputStreamReader(new BufferedInputStream(in), UTF_8); - try { - xmlReader.parse(new InputSource(reader)); - } catch (final SAXException e) { - MarketplaceClientCore.error( - NLS.bind(Messages.DefaultMarketplaceService_parseError, location.toString()), e); - throw new IOException(e.getMessage()); - } + return (T) unmarshaller.unmarshal(in, Object.class, monitor);//FIXME having T.class available here would be great... + } catch (UnmarshalException e) { + MarketplaceClientCore.error( + NLS.bind(Messages.DefaultMarketplaceService_parseError, location.toString()), e); + throw e; } finally { if (in != null) { in.close(); } } - } catch (IOException e) { + } catch (Exception e) { if (e.getCause() instanceof OperationCanceledException) { throw new CoreException(Status.CANCEL_STATUS); } @@ -156,20 +149,6 @@ public class RemoteMarketplaceService<T> { } finally { monitor.done(); } - - Object model = unmarshaller.getModel(); - if (model == null) { - // if we reach here this should never happen - throw new IllegalStateException(); - } else { - try { - return (T) model; - } catch (Exception e) { - String message = NLS.bind(Messages.DefaultMarketplaceService_unexpectedResponseContent, - model.getClass().getSimpleName()); - throw new CoreException(createErrorStatus(message, null)); - } - } } public String addMetaParameters(String uri) { @@ -210,7 +189,7 @@ public class RemoteMarketplaceService<T> { /** * The meta-parameters to be included in API requests - * + * * @param requestMetaParameters * the parameters or null if there should be none */ @@ -218,4 +197,22 @@ public class RemoteMarketplaceService<T> { this.requestMetaParameters = requestMetaParameters; } + protected static String urlEncode(String urlPart) { + try { + return URLEncoder.encode(urlPart, UTF_8); + } catch (UnsupportedEncodingException e) { + // should never happen + throw new IllegalStateException(e); + } + } + + public void activate(Map<?, ?> properties) { + if (properties != null) { + URL url = ServiceUtil.getUrl(properties, IMarketplaceService.BASE_URL, null); + if (url != null) { + setBaseUrl(url); + } + } + } + } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/SearchResult.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/SearchResult.java index 86d67b7e..53f30403 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/SearchResult.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/SearchResult.java @@ -7,15 +7,18 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; import java.util.List; +import org.eclipse.epp.mpc.core.model.ISearchResult; + /** * @author David Green */ -public class SearchResult { +public class SearchResult implements ISearchResult { private Integer matchCount; diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/ServiceUnavailableException.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/ServiceUnavailableException.java index 31839e96..d33d7cbb 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/ServiceUnavailableException.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/ServiceUnavailableException.java @@ -7,19 +7,21 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; /** * Indicates that a service is temporarily unavailable, equivalent to HTTP status code 503 - * + * * @author David Green + * @deprecated use {@link org.eclipse.epp.mpc.core.service.ServiceUnavailableException} instead */ +@Deprecated @SuppressWarnings("serial") -public class ServiceUnavailableException extends CoreException { +public class ServiceUnavailableException extends org.eclipse.epp.mpc.core.service.ServiceUnavailableException { public ServiceUnavailableException(IStatus status) { super(status); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tag.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tag.java index 6f0fd8a8..8c98d049 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tag.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tag.java @@ -7,15 +7,23 @@ * * Contributors: * Tasktop Technologies - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ITag; + /** * @author Benjamin Muskalla */ -public class Tag extends Identifiable { +public class Tag extends Identifiable implements ITag { public Tag() { } + @Override + protected boolean equalsType(Object obj) { + return obj instanceof ITag; + } + } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tags.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tags.java index 9f898cca..6e3a3646 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tags.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/Tags.java @@ -7,13 +7,16 @@ * * Contributors: * Tasktop Technologies - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.service; +import org.eclipse.epp.mpc.core.model.ITags; + /** * @author Benjamin Muskalla */ -public class Tags { +public class Tags implements ITags { protected java.util.List<Tag> tags = new java.util.ArrayList<Tag>(); diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ITransport.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ITransport.java index 4b3f6618..b8694152 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ITransport.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ITransport.java @@ -7,16 +7,14 @@ *
* Contributors:
* The Eclipse Foundation - initial API and implementation
+ * Yatta Solutions - bug 432803: public API *******************************************************************************/
package org.eclipse.epp.internal.mpc.core.util;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.net.URI;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-
-public interface ITransport {
- public InputStream stream(URI location, IProgressMonitor monitor) throws FileNotFoundException, CoreException;
+/**
+ * @deprecated moved to {@link org.eclipse.epp.mpc.core.service.ITransport}
+ */
+@Deprecated
+public interface ITransport extends org.eclipse.epp.mpc.core.service.ITransport {
}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/Messages.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/Messages.java index b496bb08..9a74d9c5 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/Messages.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/Messages.java @@ -20,6 +20,8 @@ class Messages extends NLS { public static String DefaultMarketplaceService_serviceUnavailable503;
public static String ProxyHelper_replacingAuthenticator;
+
+ public static String ServiceUtil_ignoringIncompatibleServiceProperty;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ServiceUtil.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ServiceUtil.java new file mode 100644 index 00000000..d4c652ec --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ServiceUtil.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.core.util; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Constants; + +/** + * @author Carsten Reckord + */ +public class ServiceUtil { + + /** + * Set the provided priority on a dictionary for an OSGi service registration. If the dictionary is null, + * a new one will be created and returned. + * + * @param priority the service priority + * @param dict the dictionary to change or null + * @return the provided dictionary, or a new one if the provided was null, containing a service ranking entry + * @see Constants#SERVICE_RANKING + */ + public static Dictionary<String, Object> serviceRanking(int priority, Dictionary<String, Object> dict) { + if (dict == null) { + dict = new Hashtable<String, Object>(); + } + dict.put(Constants.SERVICE_RANKING, priority); + return dict; + } + + /** + * Get a URL from a property map for the given key. If no entry exists for the key, + * or the value is not a string or it can't be parsed into an URL, the default value + * is returned. + * + * @param properties the map to extract a URL from + * @param key the key to search under + * @param defaultValue the default value returned if the entry does not exist or can't + * be converted to a URL + * @return an URL matching the string value found in the map under the given key, or the default value. + */ + public static URL getUrl(Map<?, ?> properties, String key, URL defaultValue) { + if (properties != null) { + Object value = properties.get(key); + if (value instanceof String) { + try { + return new URL((String) value); + } catch (MalformedURLException e) { + MarketplaceClientCore.error(e); + } + } else if (value != null) { + //wrong type, ignore + MarketplaceClientCore.getLog().log( + new Status(IStatus.WARNING, MarketplaceClientCore.BUNDLE_ID, NLS.bind( + Messages.ServiceUtil_ignoringIncompatibleServiceProperty, value, key))); + } + } + return defaultValue; + } + + /** + * Parse the given string to an URL. If the string can't be parsed, an error is logged + * and null is returned + * + * @param url the url string to parse + * @return the value as an URL, or null if there was a parse error + */ + public static URL parseUrl(String url) { + try { + return new URL(url); + } catch (MalformedURLException e) { + MarketplaceClientCore.error(e); + return null; + } + } + +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/TransportFactory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/TransportFactory.java index 4165adcf..efbc4571 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/TransportFactory.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/TransportFactory.java @@ -7,6 +7,7 @@ *
* Contributors:
* The Eclipse Foundation - initial API and implementation
+ * Yatta Solutions - bug 432803: public API *******************************************************************************/
package org.eclipse.epp.internal.mpc.core.util;
@@ -14,21 +15,29 @@ import java.io.FileNotFoundException; import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
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.epp.internal.mpc.core.MarketplaceClientCore;
+import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin;
import org.eclipse.epp.internal.mpc.core.service.ServiceUnavailableException;
+import org.eclipse.epp.mpc.core.service.ITransportFactory;
+import org.eclipse.epp.mpc.core.service.ServiceHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
/**
* Factory to retrieve Transport instances of p2. Will delegate to version-dependent implementations.
- *
+ *
* @author David Green
* @author Benjamin Muskalla
+ * @author Carsten Reckord
*/
-public abstract class TransportFactory {
+public abstract class TransportFactory implements ITransportFactory {
private static final String[] factoryClasses = new String[] { //
"org.eclipse.epp.internal.mpc.core.util.P2TransportFactory", // //$NON-NLS-1$
@@ -37,34 +46,63 @@ public abstract class TransportFactory { private static TransportFactory instance;
+ /**
+ * @deprecated use registered {@link ITransportFactory} OSGi service
+ * @see ServiceHelper#getTransportFactory()
+ */
+ @Deprecated
public static synchronized TransportFactory instance() {
if (instance == null) {
- for (String factoryClass : factoryClasses) {
- TransportFactory factory;
- try {
- factory = (TransportFactory) Class.forName(factoryClass,true,TransportFactory.class.getClassLoader()).newInstance();
- } catch (Throwable t) {
- // ignore
- continue;
- }
- if (factory.isAvailable()) {
- instance = factory;
- break;
- }
- }
- if (instance == null) {
+ List<ITransportFactory> availableFactories = listAvailableFactories();
+ if (availableFactories.isEmpty()) {
throw new IllegalStateException();
}
+ instance = (TransportFactory) availableFactories.get(0);
}
return instance;
}
+ public static org.eclipse.epp.mpc.core.service.ITransport createTransport() {
+ //search for registered factory service
+ BundleContext context = MarketplaceClientCorePlugin.getBundle().getBundleContext();
+ ServiceReference<ITransportFactory> serviceReference = context.getServiceReference(ITransportFactory.class);
+ if (serviceReference != null) {
+ ITransportFactory transportService = context.getService(serviceReference);
+ if (transportService != null) {
+ try {
+ return transportService.getTransport();
+ } finally {
+ context.ungetService(serviceReference);
+ }
+ }
+ }
+ //fall back to legacy transports
+ return instance().getTransport();
+ }
+
+ public static List<ITransportFactory> listAvailableFactories() {
+ List<ITransportFactory> factories = new ArrayList<ITransportFactory>();
+ for (String factoryClass : factoryClasses) {
+ TransportFactory factory;
+ try {
+ factory = (TransportFactory) Class.forName(factoryClass, true, TransportFactory.class.getClassLoader())
+ .newInstance();
+ } catch (Throwable t) {
+ // ignore
+ continue;
+ }
+ if (factory.isAvailable()) {
+ factories.add(factory);
+ }
+ }
+ return factories;
+ }
public ITransport getTransport() {
return new ITransport() {
public InputStream stream(URI location, IProgressMonitor monitor) throws FileNotFoundException,
- CoreException {
+ org.eclipse.epp.mpc.core.service.ServiceUnavailableException, CoreException {
try {
return invokeStream(location, monitor);
} catch (Exception e) {
@@ -108,5 +146,4 @@ public abstract class TransportFactory { }
}
}
-
}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/messages.properties b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/messages.properties index 9e1cf227..0dfe7cff 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/messages.properties +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/messages.properties @@ -1,3 +1,4 @@ P2TransportFactory_AuthenticationFailed=Authentication failed: {0} ProxyHelper_replacingAuthenticator=Unable to read default network authenticator - existing authenticator will be replaced -DefaultMarketplaceService_serviceUnavailable503=Marketplace service is temporarily unavailable. Please try again later.
\ No newline at end of file +DefaultMarketplaceService_serviceUnavailable503=Marketplace service is temporarily unavailable. Please try again later. +ServiceUtil_ignoringIncompatibleServiceProperty=Ignoring value '{0}' for service property '{1}' - incompatible type. diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalog.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalog.java new file mode 100644 index 00000000..efe03f3f --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalog.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import org.eclipse.epp.mpc.core.service.ICatalogService; + +/** + * A catalog describes an entry point to a marketplace server. Its {@link #getUrl() url} is the base of the Marketplace + * REST API. It has a description, image and optional additional provider branding information, which can be used to + * present the marketplace to users, e.g. in the Marketplace Wizard. + * + * @see ICatalogService + * @see https://wiki.eclipse.org/Marketplace/REST + * @author Benjamin Muskalla + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICatalog extends IIdentifiable { + + /** + * If the catalog is self-contained, then a {@link INode node} installation will only use the node's + * {@link INode#getUpdateurl() update url} and the catalog's {@link #getDependencyRepository() dependency + * repository}. Otherwise all known repositories are consulted. + * + * @return true if this catalog is self-contained, false if all known repositories should be used during + * installation + */ + boolean isSelfContained(); + + /** + * @return this catalog's description suitable for presentation to the user. + */ + String getDescription(); + + /** + * @return a URL to an image resource used to present this catalog in a catalog chooser. May be null. + */ + String getImageUrl(); + + /** + * @return additional branding information + */ + ICatalogBranding getBranding(); + + /** + * An optional URI to a repository from which dependencies may be installed, may be null. + * + * @return the URI to use for dependency resolution, or null. + */ + String getDependencyRepository(); + + /** + * Each catalog can optionally point to a current news entry, e.g. to present the user with a newsletter. + * + * @return the current news entry for this catalog, or null. + */ + INews getNews(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java new file mode 100644 index 00000000..672a39de --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogBranding.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +/** + * Branding information for a marketplace catalog entry. + * + * @see ICatalog + * @author Benjamin Muskalla + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICatalogBranding extends IIdentifiable { + + String getWizardIcon(); + + boolean hasSearchTab(); + + String getSearchTabName(); + + boolean hasPopularTab(); + + String getPopularTabName(); + + boolean hasRecentTab(); + + String getRecentTabName(); + + String getWizardTitle(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogs.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogs.java new file mode 100644 index 00000000..b9bc5734 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICatalogs.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * A list of catalogs. + * + * @see ICatalog + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICatalogs { + + List<? extends ICatalog> getCatalogs(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategories.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategories.java new file mode 100644 index 00000000..9a3da357 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategories.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * A list of categories. + * + * @see ICategory + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICategories { + + List<? extends ICategory> getCategory(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategory.java new file mode 100644 index 00000000..0dc7c9f3 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ICategory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +import org.eclipse.epp.mpc.core.service.IMarketplaceService; + +/** + * Marketplaces are categorized in {@link IMarket markets} and {@link ICategory categories}. Each category can occur in + * one or more markets and can be associated with any number of {@link #getNode() nodes}. + * + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICategory extends IIdentifiable { + + /** + * @return the number of {@link #getNode() nodes} in this category + */ + Integer getCount(); + + /** + * A list of nodes for this category. Entries in this list are typically not fully realized. They will only have + * their {@link INode#getId() ids} and {@link INode#getName() names} set. Use + * {@link IMarketplaceService#getNode(INode, org.eclipse.core.runtime.IProgressMonitor) the marketplace service} to + * retrieve a fully realized node instance from the marketplace server. + * + * @return the list of nodes in this category. + */ + List<? extends INode> getNode(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIdentifiable.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIdentifiable.java new file mode 100644 index 00000000..867b02af --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIdentifiable.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +/** + * Base class for marketplace entities like nodes or categories. Instances are identified by an id unique to their + * {@link ICatalog marketplace server} and/or their url. Optionally, they may have a name suitable for presentation to + * the user. + * + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IIdentifiable { + + /** + * @return this element's unique id in its {@link ICatalog catalog} + */ + String getId(); + + /** + * @return this element's name + */ + String getName(); + + /** + * @return the URL from which this element can be re-retrieved from the marketplace server + */ + String getUrl(); + + /** + * Check if the given object's type and id match. + * + * @param obj + * the object to compare (can be null) + * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getId() id} as this object + */ + boolean equalsId(Object obj); + + /** + * Check if the given object's type and url match. + * + * @param obj + * the object to compare (can be null) + * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getUrl() url} as this object + */ + boolean equalsUrl(Object obj); + + /** + * Check if the given object's type and name match. + * + * @param obj + * the object to compare (can be null) + * @return true if <code>obj</code> has the same {@link #getClass() type} and {@link #getName() name} as this object + */ + boolean equalsName(Object obj); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIus.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIus.java new file mode 100644 index 00000000..f4d35b15 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IIus.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * A list of installable units for an installable marketplace {@link INode node} + * + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IIus { + + List<String> getIu(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IMarket.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IMarket.java new file mode 100644 index 00000000..cd25cc39 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IMarket.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * Marketplaces are categorized in {@link IMarket markets} and {@link ICategory categories}. Each market can have a + * number of categories, which in turn can be associated with {@link INode nodes}. + * + * @see ICategory + * @see INode + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMarket extends IIdentifiable { + + List<? extends ICategory> getCategory(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INews.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INews.java new file mode 100644 index 00000000..7ae3483b --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INews.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +/** + * Information about a published news item for a catalog. This can be used to e.g. integrate a regularly published + * newsletter with the marketplace wizard. + * + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface INews { + + /** + * @return the URL of the published news item + */ + String getUrl(); + + /** + * @return a short news title suitable to be presented before the actual news is opened. + */ + String getShortTitle(); + + /** + * @return a timestamp for the last update to the news. Any change to the published news should result in an updated + * timestamp. + */ + Long getTimestamp(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INode.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INode.java new file mode 100644 index 00000000..0700a0fc --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/INode.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.Date; + +/** + * A node represents an entry on a marketplace. It is associated with one or more categories, under which it is listed. + * Additionally, tags can be specified to define related technologies. + * <p> + * A node contains all information about a marketplace entry necessary to present it to users, including a + * {@link #getName()}, {@link #getOwner() owner}, {@link #getShortdescription() short} and {@link #getBody() long} + * description, {@link #getImage() icon} and optional {@link #getScreenshot()}. Some social feedback on the node entry + * is provided by means of its {@link #getInstallsTotal() total} and {@link #getInstallsRecent() recent} installation + * counts, as well as the number of {@link #getFavorited() favorite votes} it has received. + * <p> + * Nodes can describe different kinds of {@link #getType() contributions}, like installable Eclipse plug-ins, consulting + * services and so on. In case of installable Eclipse plug-ins, the {@link #getIus() installable units} are provided for + * installation from the node's {@link #getUpdateurl() update site}. + * + * @author David Green + * @author Benjamin Muskalla + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface INode extends IIdentifiable { + + /** + * The number of times this node has been favorited. + */ + Integer getFavorited(); + + /** + * The number of times this node has been installed. + */ + Integer getInstallsTotal(); + + /** + * The number of times this node has been installed recently (last 30 days). + */ + Integer getInstallsRecent(); + + /** + * The type of listing, for example 'resource' or 'training'. + */ + String getType(); + + /** + * the categories of this listing. + */ + ICategories getCategories(); + + ITags getTags(); + + String getOwner(); + + /** + * The short description of this listing, may include HTML markup (escaped). Note that the short description may or + * may not be shorter than the body. + */ + String getShortdescription(); + + /** + * The description of this listing, may include HTML markup (escaped). + */ + String getBody(); + + /** + * The time of creation for this entry. + */ + Date getCreated(); + + /** + * The last change time for this entry. + */ + Date getChanged(); + + /** + * @return true if this node's owner is a foundation member, false otherwise, null if unknown. + */ + Boolean getFoundationmember(); + + /** + * An URL for the homepage for this entry or its owner. + */ + String getHomepageurl(); + + /** + * The image used as this entry's logo + */ + String getImage(); + + /** + * An optional screenshot used in conjunction with the {@link #getBody() full description}. + */ + String getScreenshot(); + + /** + * The version of the solution represented by this node. It is encouraged to use a valid OSGi version, but this + * isn't guaranteed. + */ + String getVersion(); + + /** + * The license for the plug-in represented by this node, e.g. 'EPL'. + */ + String getLicense(); + + /** + * The owner's company name + */ + String getCompanyname(); + + /** + * The development status of this plug-in entry, e.g. "Production/Stable" + */ + String getStatus(); + + /** + * A comma-separated list of supported Eclipse versions. Currently, this can take any form, although it is + * encouraged to use a comma-separated list of Eclipse versions like "3.6-3.8, 4.2.1, 4.2.2, 4.3". + * <p> + * This might get more standardized in the future. + */ + String getEclipseversion(); + + /** + * @return a contact URL to get support for this entry + */ + String getSupporturl(); + + /** + * The URL of an Eclipse update site containing this entry's {@link #getIus() installable units}. + */ + String getUpdateurl(); + + /** + * The installable units that will be installed for this node. + */ + IIus getIus(); + + /** + * The supported platforms under which this plug-in node can be installed. + */ + IPlatforms getPlatforms(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IPlatforms.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IPlatforms.java new file mode 100644 index 00000000..d8f0711a --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/IPlatforms.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IPlatforms { + + List<String> getPlatform(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ISearchResult.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ISearchResult.java new file mode 100644 index 00000000..123f8906 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ISearchResult.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +import org.eclipse.epp.mpc.core.service.IMarketplaceService; + +/** + * Search results returned by the marketplace server through the {@link IMarketplaceService}. The actual number of + * returned nodes might be less than the number of matches on the server. In that case, the {@link #getMatchCount() + * match count} reflects the number of actual matches and the {@link #getNodes() returned results} are a subset of all + * matches. + * + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ISearchResult { + + /** + * The number of matches that matched the query, which may not be equal to the number of nodes returned. + */ + Integer getMatchCount(); + + /** + * The nodes that were matched by the query + */ + List<? extends INode> getNodes(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITag.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITag.java new file mode 100644 index 00000000..f547f555 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITag.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +/** + * A simple tag that can be associated with nodes to give additional information about related topics. + * + * @author Benjamin Muskalla + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITag extends IIdentifiable { + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITags.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITags.java new file mode 100644 index 00000000..a966a38f --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/model/ITags.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.model; + +import java.util.List; + +/** + * A list of tags. + * + * @see ITag + * @author Benjamin Muskalla + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITags { + + List<? extends ITag> getTags(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ICatalogService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ICatalogService.java new file mode 100644 index 00000000..e0f02eb2 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ICatalogService.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.epp.mpc.core.model.ICatalog; + +/** + * Entry point to the marketplace API. A catalog service is used to retrieve a list of known catalogs that implement the + * <a href="https://wiki.eclipse.org/Marketplace/REST">Marketplace REST API</a>. An instance of this class can be + * retrieved through the {@link IMarketplaceServiceLocator} OSGi service. + * + * @see ICatalog + * @see IMarketplaceService + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICatalogService { + + List<? extends ICatalog> listCatalogs(IProgressMonitor monitor) throws CoreException; + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceService.java new file mode 100644 index 00000000..f0a9a652 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceService.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.epp.mpc.core.model.ICategory; +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; + +/** + * A service that provides access to the marketplace and implements the <a + * href="https://wiki.eclipse.org/Marketplace/REST">Marketplace REST API</a>. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * @author David Green + * @author Carsten Reckord + */ +public interface IMarketplaceService { + + /** + * Property key for registered IMarketplaceService OSGi services indicating the marketplace's base URL. + */ + public static final String BASE_URL = "url"; //$NON-NLS-1$ + + /** + * Get a list of all markets. This is the entrypoint to the marketplace. + */ + List<? extends IMarket> listMarkets(IProgressMonitor monitor) throws CoreException; + + /** + * Get a market by its id + * + * @param market + * the market which must have an {@link IMarket#getUrl() url}. + * @return the identified node + */ + IMarket getMarket(IMarket market, IProgressMonitor monitor) throws CoreException; + + /** + * Get a category by its id + * + * @param category + * A category which must have an {@link ICategory#getUrl() url}. + * @return the identified category + */ + ICategory getCategory(ICategory category, IProgressMonitor monitor) throws CoreException; + + /** + * Get a node by its id + * + * @param node + * the node which must either have an {@link INode#getUrl() url} or an {@link INode#getId() id}. + * @return the identified node + */ + INode getNode(INode node, IProgressMonitor monitor) throws CoreException; + + /** + * Find nodes in the marketplace with a text query, and optionally specify the market/category + * + * @param market + * the market to search in, or null if the search should span all markets + * @param category + * the category to search in, or null if the search should span all categories + * @param queryText + * the query text, must not be null + * @return the search result + */ + ISearchResult search(IMarket market, ICategory category, String queryText, IProgressMonitor monitor) + throws CoreException; + + /** + * Find featured nodes in the marketplace + * + * @return the search result + */ + ISearchResult featured(IProgressMonitor monitor) throws CoreException; + + /** + * Find featured nodes in the marketplace + * + * @param market + * the market in which to return featured, or null if featured should include all markets + * @param category + * the category in which to return fetured, or null if featured should include all categories + * @return the search result + */ + ISearchResult featured(IMarket market, ICategory category, IProgressMonitor monitor) throws CoreException; + + /** + * Find recently added/modified nodes in the marketplace + * + * @return the search result + */ + ISearchResult recent(IProgressMonitor monitor) throws CoreException; + + /** + * Find most-favorited nodes in the marketplace + * + * @return the search result + */ + ISearchResult favorites(IProgressMonitor monitor) throws CoreException; + + /** + * Find most active nodes in the marketplace + * + * @return the search result + */ + ISearchResult popular(IProgressMonitor monitor) throws CoreException; + + /** + * Get the news configuration for the marketplace + * + * @return the news configuration + */ + INews news(IProgressMonitor monitor) throws CoreException; + + /** + * Report an error in resolving an install operation. + * + * @param result + * the status of the install operation + * @param nodes + * the nodes that were included in the install, or null if unknown. + * @param iuIdsAndVersions + * the IUs and their versions (comma-delimited), or null if unknown. + * @param resolutionDetails + * the detailed error message, or null if unknown. + * @param monitor + * @noreference This method is not intended to be called by clients directly. It should only ever be called as part + * of an install operation. + */ + void reportInstallError(IStatus result, Set<? extends INode> nodes, Set<String> iuIdsAndVersions, + String resolutionDetails, IProgressMonitor monitor) throws CoreException; + + /** + * Report a successful install. + * + * @param node + * the installed node + * @param monitor + * @noreference This method is not intended to be called by clients directly. It should only ever be called as part + * of an install operation. + */ + void reportInstallSuccess(INode node, IProgressMonitor monitor); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceServiceLocator.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceServiceLocator.java new file mode 100644 index 00000000..b1dbc575 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceServiceLocator.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.osgi.framework.BundleContext; + +/** + * This service manages instances of {@link IMarketplaceService} and {@link ICatalogService} for accessing marketplace + * servers. An instance of this service can be retrieved from the OSGi {@link BundleContext#getServiceReference(Class) + * service registry}. + * <p> + * This service references a single {@link ICatalogService} for catalog {@link #getCatalogService() discovery}. For each + * of the discovered catalogs, a {@link IMarketplaceService marketplace service} can be + * {@link #getMarketplaceService(String) acquired} using the catalog's {@link ICatalog#getUrl() base url}. + * <p> + * The default implementation of this service will look for registered {@link ICatalogService} and + * {@link IMarketplaceService} instances with matching url paramters in the OSGi service registry and return matching + * services. If no match is found, the service locator will create a new instance and return this on subsequent calls. + * + * @author David Green + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMarketplaceServiceLocator { + + /** + * Property key for registered IMarketplaceServiceLocator OSGi services indicating the URL of the default + * marketplace and catalog service. + * <p> + * This is a convenience property to use a common value for + * {@link IMarketplaceServiceLocator#DEFAULT_MARKETPLACE_URL} and {@link #CATALOG_URL} + * + * @see #DEFAULT_MARKETPLACE_URL + * @see #CATALOG_URL + */ + public static final String DEFAULT_URL = "url"; //$NON-NLS-1$ + + /** + * Property key for registered IMarketplaceServiceLocator OSGi services indicating the URL of the default + * marketplace service. + * + * @see #DEFAULT_URL + * @see #CATALOG_URL + */ + public static final String DEFAULT_MARKETPLACE_URL = "marketplaceUrl"; //$NON-NLS-1$ + + /** + * Property key for registered IMarketplaceServiceLocator OSGi services indicating the URL of the catalog service. + * + * @see #DEFAULT_URL + * @see #DEFAULT_MARKETPLACE_URL + */ + public static final String CATALOG_URL = "catalogUrl"; //$NON-NLS-1$ + + /** + * Same as {@link #getMarketplaceService(String) getMarketplaceService(DEFAULT_MARKETPLACE_URL)} + * + * @return a marketplace service for the {@link #DEFAULT_MARKETPLACE_URL default marketplace url} + */ + IMarketplaceService getDefaultMarketplaceService(); + + /** + * Get a marketplace service for the given base url. The OSGi registry is searched for a registered instance + * matching the url. If none is found, a new instance is created and ued for subsequent calls. + */ + IMarketplaceService getMarketplaceService(String baseUrl); + + /** + * Get a catalog service for the default {@link #CATALOG_URL discovery url}. + */ + ICatalogService getCatalogService(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceUnmarshaller.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceUnmarshaller.java new file mode 100644 index 00000000..beaacc48 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/IMarketplaceUnmarshaller.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * This service provides unmarshalling support for the data returned by the <a + * href="https://wiki.eclipse.org/Marketplace/REST">Marketplace REST API</a>. + * + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMarketplaceUnmarshaller { + /** + * Parse the input stream into an object of the given type. + * + * @throws IOException + * if an error occurs while reading from the stream + * @throws UnmarshalException + * if an error occurs while parsing the input, including unexpected content or content that doesn't + * match the given type. + */ + public <T> T unmarshal(InputStream in, Class<T> type, IProgressMonitor monitor) throws UnmarshalException, + IOException; +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransport.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransport.java new file mode 100644 index 00000000..5779d310 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransport.java @@ -0,0 +1,29 @@ +/*******************************************************************************
+ * Copyright (c) 2014 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * The Eclipse Foundation - initial API and implementation
+ * Yatta Solutions - bug 432803: public API + *******************************************************************************/
+package org.eclipse.epp.mpc.core.service;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * An abstraction for a URI-based download channel. The actual download strategy depends on the implementation.
+ *
+ * @author Carsten Reckord
+ */
+public interface ITransport {
+ public InputStream stream(URI location, IProgressMonitor monitor) throws FileNotFoundException,
+ ServiceUnavailableException, CoreException;
+}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransportFactory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransportFactory.java new file mode 100644 index 00000000..637b13c9 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ITransportFactory.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +/** + * Factory to retrieve Transport instances of p2. Will delegate to version-dependent implementations. + * + * @author David Green + * @author Benjamin Muskalla + * @author Carsten Reckord + */ +public interface ITransportFactory { + + ITransport getTransport(); + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/QueryHelper.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/QueryHelper.java new file mode 100644 index 00000000..8e83e169 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/QueryHelper.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import org.eclipse.epp.internal.mpc.core.service.Category; +import org.eclipse.epp.internal.mpc.core.service.Identifiable; +import org.eclipse.epp.internal.mpc.core.service.Market; +import org.eclipse.epp.internal.mpc.core.service.Node; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; + +/** + * Factory for marketplace model instances suitable to use as input for {@link IMarketplaceService} requests. + * + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class QueryHelper { + + /** + * @return a node instance that can be used to look up a matching node on + * the marketplace by id. + */ + public static INode nodeById(String id) { + return withId(new Node(), id); + } + + /** + * @return a node instance that can be used to look up a matching node on + * the marketplace by url. + */ + public static INode nodeByUrl(String url) { + return withUrl(new Node(), url); + } + + /** + * @return a category instance that can be used to look up a matching category on + * the marketplace by id. + */ + public static ICategory categoryById(String id) { + return withId(new Category(), id); + } + + /** + * @return a category instance that can be used to look up a matching category on + * the marketplace by url. + */ + public static ICategory categoryByUrl(String url) { + return withUrl(new Category(), url); + } + + /** + * @return a category instance that can be used to look up a matching category on + * the marketplace by name. + */ + public static ICategory categoryByName(String name) { + return withName(new Category(), name); + } + + /** + * @return a market instance that can be used to look up a matching market on + * the marketplace by id. + */ + public static IMarket marketById(String id) { + return withId(new Market(), id); + } + + /** + * @return a market instance that can be used to look up a matching market on + * the marketplace by url. + */ + public static IMarket marketByUrl(String url) { + return withUrl(new Market(), url); + } + + /** + * @return a market instance that can be used to look up a matching market on + * the marketplace by name. + */ + public static IMarket marketByName(String name) { + return withName(new Market(), name); + } + + private static <T extends Identifiable> T withId(T identifiable, String id) { + identifiable.setId(id); + return identifiable; + } + + private static <T extends Identifiable> T withUrl(T identifiable, String url) { + identifiable.setUrl(url); + return identifiable; + } + + private static <T extends Identifiable> T withName(T identifiable, String name) { + identifiable.setName(name); + return identifiable; + } +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceHelper.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceHelper.java new file mode 100644 index 00000000..81701519 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceHelper.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; + +/** + * Convenience class to access marketplace-related OSGi services. + * + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public abstract class ServiceHelper { + + private static ServiceHelper getInstance() { + return MarketplaceClientCorePlugin.getDefault().getServiceHelper(); + } + + protected abstract IMarketplaceServiceLocator doGetMarketplaceServiceLocator(); + + protected abstract ITransportFactory doGetTransportFactory(); + + protected abstract IMarketplaceUnmarshaller doGetMarketplaceUnmarshaller(); + + public static IMarketplaceServiceLocator getMarketplaceServiceLocator() { + ServiceHelper instance = getInstance(); + return instance == null ? null : instance.doGetMarketplaceServiceLocator(); + } + + public static ITransportFactory getTransportFactory() { + ServiceHelper instance = getInstance(); + return instance == null ? null : instance.doGetTransportFactory(); + } + + public static IMarketplaceUnmarshaller getMarketplaceUnmarshaller() { + ServiceHelper instance = getInstance(); + return instance == null ? null : instance.doGetMarketplaceUnmarshaller(); + } + +}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceUnavailableException.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceUnavailableException.java new file mode 100644 index 00000000..a2919fc7 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/ServiceUnavailableException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; + +/** + * Indicates that a service is temporarily unavailable, equivalent to HTTP status code 503 + * + * @author David Green + */ +@SuppressWarnings("serial") +public class ServiceUnavailableException extends CoreException { + + public ServiceUnavailableException(IStatus status) { + super(status); + } + +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/UnmarshalException.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/UnmarshalException.java new file mode 100644 index 00000000..78696f4a --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/mpc/core/service/UnmarshalException.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.core.service; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; + +public class UnmarshalException extends CoreException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public UnmarshalException(IStatus status) { + super(status); + } + +} diff --git a/org.eclipse.epp.mpc.tests/META-INF/MANIFEST.MF b/org.eclipse.epp.mpc.tests/META-INF/MANIFEST.MF index 05c6d4b6..df9c3e6b 100644 --- a/org.eclipse.epp.mpc.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.epp.mpc.tests/META-INF/MANIFEST.MF @@ -13,7 +13,14 @@ Require-Bundle: org.eclipse.osgi;bundle-version="3.6.0", org.eclipse.equinox.p2.repository;bundle-version="2.0.0", org.eclipse.equinox.p2.core;bundle-version="2.0.0", org.eclipse.equinox.p2.discovery, - org.eclipse.jface;bundle-version="3.6.0" + org.eclipse.jface;bundle-version="3.6.0", + org.eclipse.ui;bundle-version="3.106.0", + org.eclipse.swtbot.eclipse.finder;bundle-version="2.2.1", + org.eclipse.swtbot.junit4_x;bundle-version="2.2.1", + org.apache.log4j;bundle-version="1.2.15", + org.eclipse.equinox.p2.ui.discovery;bundle-version="1.0.0", + org.hamcrest.library;bundle-version="1.3.0", + org.eclipse.core.net;bundle-version="1.2.200" Import-Package: org.eclipse.ecf.core;version="3.0.0", org.eclipse.ecf.core.util, org.eclipse.ecf.filetransfer, diff --git a/org.eclipse.epp.mpc.tests/pom.xml b/org.eclipse.epp.mpc.tests/pom.xml index 6d8757b2..e97224d0 100644 --- a/org.eclipse.epp.mpc.tests/pom.xml +++ b/org.eclipse.epp.mpc.tests/pom.xml @@ -22,6 +22,7 @@ <artifactId>tycho-surefire-plugin</artifactId> <configuration> <useUIHarness>true</useUIHarness> + <useUIThread>false</useUIThread> <forkedProcessTimeoutInSeconds>600</forkedProcessTimeoutInSeconds> <product>org.eclipse.sdk.ide</product> <application>org.eclipse.ui.ide.workbench</application> diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/AllTests.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/AllTests.java index 115b682b..735f4734 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/AllTests.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/AllTests.java @@ -10,15 +10,6 @@ *******************************************************************************/ package org.eclipse.epp.mpc.tests; -import org.eclipse.epp.mpc.tests.service.CatalogServiceTest; -import org.eclipse.epp.mpc.tests.service.DefaultMarketplaceServiceTest; -import org.eclipse.epp.mpc.tests.service.xml.UnmarshallerTest; -import org.eclipse.epp.mpc.tests.ui.catalog.CatalogDescriptorTest; -import org.eclipse.epp.mpc.tests.ui.catalog.MarketplaceInfoTest; -import org.eclipse.epp.mpc.tests.ui.wizard.MarketplaceUrlHandlerTest; -import org.eclipse.epp.mpc.tests.ui.wizard.SelectionModelStateSerializerTest; -import org.eclipse.epp.mpc.tests.util.TextUtilTest; -import org.eclipse.epp.mpc.tests.util.TransportFactoryTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @@ -28,17 +19,8 @@ import org.junit.runners.Suite.SuiteClasses; */ @RunWith(Suite.class) @SuiteClasses({ // - UnmarshallerTest.class, // - DefaultMarketplaceServiceTest.class, // - TextUtilTest.class, // - SelectionModelStateSerializerTest.class, // - MarketplaceUrlHandlerTest.class, // - TransportFactoryTest.class, // - MarketplaceInfoTest.class, // - CatalogServiceTest.class, // - CatalogDescriptorTest.class // - + UITests.class, // + BotTests.class // }) public class AllTests { - } diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/BotTests.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/BotTests.java new file mode 100644 index 00000000..09173c50 --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/BotTests.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.tests; + +import org.eclipse.epp.mpc.tests.ui.wizard.MarketplaceClientServiceTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** + * @author David Green + */ +@RunWith(Suite.class) +@SuiteClasses({ // + MarketplaceClientServiceTest.class +}) +public class BotTests { + +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UISuite.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UISuite.java new file mode 100644 index 00000000..76837aea --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UISuite.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.epp.mpc.tests; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +public class UISuite extends Suite { + + public UISuite(Class<?> klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + } + + public UISuite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError { + super(builder, classes); + } + + void doRun(RunNotifier notifier) { + super.run(notifier); + } + + @Override + public void run(final RunNotifier notifier) { + if (!PlatformUI.isWorkbenchRunning()) { + notifier.fireTestFailure(new Failure(getDescription(), new IllegalStateException("Workbench not running"))); + } + if (Display.getCurrent() != null) { + super.run(notifier);//we are in an UI Thread already + } else { + final Display display = PlatformUI.getWorkbench().getDisplay(); + display.syncExec(new Runnable() { + public void run() { + doRun(notifier); + } + }); + } + } + +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UITests.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UITests.java new file mode 100644 index 00000000..59d35200 --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/UITests.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + *******************************************************************************/ +package org.eclipse.epp.mpc.tests; + +import org.eclipse.epp.mpc.tests.service.CatalogServiceTest; +import org.eclipse.epp.mpc.tests.service.DefaultMarketplaceServiceTest; +import org.eclipse.epp.mpc.tests.service.xml.UnmarshallerTest; +import org.eclipse.epp.mpc.tests.ui.catalog.CatalogDescriptorTest; +import org.eclipse.epp.mpc.tests.ui.catalog.MarketplaceInfoTest; +import org.eclipse.epp.mpc.tests.ui.wizard.MarketplaceUrlHandlerTest; +import org.eclipse.epp.mpc.tests.ui.wizard.SelectionModelStateSerializerTest; +import org.eclipse.epp.mpc.tests.util.TextUtilTest; +import org.eclipse.epp.mpc.tests.util.TransportFactoryTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * @author David Green + */ +@RunWith(UISuite.class) +@SuiteClasses({ // + UnmarshallerTest.class, // + DefaultMarketplaceServiceTest.class, // + TextUtilTest.class, // + SelectionModelStateSerializerTest.class, // + MarketplaceUrlHandlerTest.class, // + TransportFactoryTest.class, // + MarketplaceInfoTest.class, // + CatalogServiceTest.class, // + CatalogDescriptorTest.class // + +}) +public class UITests { + +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/CatalogServiceTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/CatalogServiceTest.java index 7dd05d1d..a45d2ffd 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/CatalogServiceTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/CatalogServiceTest.java @@ -7,12 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.service; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.util.Collections; import java.util.List; @@ -20,14 +19,22 @@ import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; import org.eclipse.epp.internal.mpc.core.ServiceLocator; import org.eclipse.epp.internal.mpc.core.service.Catalog; import org.eclipse.epp.internal.mpc.core.service.CatalogService; +import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.eclipse.epp.mpc.core.service.ICatalogService; +import org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; /** * @author Benjamin Muskalla @@ -43,23 +50,29 @@ public class CatalogServiceTest { } } - private CatalogService catalogService; + private ICatalogService catalogService; - private ServiceLocator serviceLocator; + private IMarketplaceServiceLocator serviceLocator; + + private ServiceReference<IMarketplaceServiceLocator> serviceLocatorReference; + + private BundleContext bundleContext; @Before public void setUp() throws Exception { - serviceLocator = ServiceLocator.getInstance(); + bundleContext = MarketplaceClientCorePlugin.getBundle().getBundleContext(); + serviceLocatorReference = bundleContext.getServiceReference(IMarketplaceServiceLocator.class); + serviceLocator = bundleContext.getService(serviceLocatorReference); catalogService = serviceLocator.getCatalogService(); } @Test public void listCatalogs() throws CoreException { - List<Catalog> catalogs = catalogService.listCatalogs(new NullProgressMonitor()); + List<? extends ICatalog> catalogs = catalogService.listCatalogs(new NullProgressMonitor()); assertNotNull(catalogs); assertFalse(catalogs.isEmpty()); - for (Catalog catalog : catalogs) { + for (ICatalog catalog : catalogs) { assertNotNull(catalog.getId()); assertNotNull(catalog.getUrl()); assertNotNull(catalog.getName()); @@ -68,20 +81,31 @@ public class CatalogServiceTest { @Test public void testSampleCatalog() throws Exception { - ServiceLocator.setInstance(new ServiceLocator() { - @Override - public CatalogService getCatalogService() { - return new MockCatalogService(); - } - }); - catalogService = ServiceLocator.getInstance().getCatalogService(); - List<Catalog> catalogs = catalogService.listCatalogs(null); - assertEquals(1, catalogs.size()); - assertEquals("mock", catalogs.get(0).getId()); + // ServiceLocator oldInstance = ServiceLocator.getInstance(); + // ServiceLocator.setInstance(new ServiceLocator() { + // @Override + // public ICatalogService getCatalogService() { + // return new MockCatalogService(); + // } + // }); + ServiceRegistration<ICatalogService> registration = bundleContext.registerService(ICatalogService.class, + new MockCatalogService(), ServiceUtil.serviceRanking(Integer.MAX_VALUE, null)); + try { + catalogService = ServiceLocator.getInstance().getCatalogService(); + List<? extends ICatalog> catalogs = catalogService.listCatalogs(null); + assertEquals(1, catalogs.size()); + assertEquals("mock", catalogs.get(0).getId()); + } finally { + // ServiceLocator.setInstance(oldInstance); + registration.unregister(); + } } @After public void tearDown() { - ServiceLocator.setInstance(serviceLocator); + serviceLocator = null; + bundleContext.ungetService(serviceLocatorReference); + serviceLocatorReference = null; + bundleContext = null; } } diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/DefaultMarketplaceServiceTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/DefaultMarketplaceServiceTest.java index dcca279d..cbce24a3 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/DefaultMarketplaceServiceTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/DefaultMarketplaceServiceTest.java @@ -7,14 +7,12 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API * Yatta Solutions - bug 397004 *******************************************************************************/ package org.eclipse.epp.mpc.tests.service; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.util.HashMap; import java.util.HashSet; @@ -28,9 +26,11 @@ import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.service.Category; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.core.service.RemoteMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.SearchResult; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.model.ISearchResult; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,28 +56,27 @@ public class DefaultMarketplaceServiceTest { @Test public void listMarkets() throws CoreException { - List<Market> markets = marketplaceService.listMarkets(new NullProgressMonitor()); + List<? extends IMarket> markets = marketplaceService.listMarkets(new NullProgressMonitor()); assertNotNull(markets); assertFalse(markets.isEmpty()); - for (Market market : markets) { + for (IMarket market : markets) { assertNotNull(market.getId()); assertNotNull(market.getUrl()); assertNotNull(market.getName()); } } - @SuppressWarnings("null") @Test public void getCategory() throws CoreException { - List<Market> markets = marketplaceService.listMarkets(new NullProgressMonitor()); + List<? extends IMarket> markets = marketplaceService.listMarkets(new NullProgressMonitor()); assertNotNull(markets); assertFalse(markets.isEmpty()); final String marketName = "Tools"; - Market market = null; - for (Market m : markets) { + IMarket market = null; + for (IMarket m : markets) { if (marketName.equals(m.getName())) { market = m; break; @@ -89,8 +88,8 @@ public class DefaultMarketplaceServiceTest { final String categoryName = "Mylyn Connectors"; - Category category = null; - for (Category c : market.getCategory()) { + ICategory category = null; + for (ICategory c : market.getCategory()) { if (categoryName.equals(c.getName())) { category = c; break; @@ -98,7 +97,7 @@ public class DefaultMarketplaceServiceTest { } assertNotNull("Expected category " + categoryName, category); - Category result = marketplaceService.getCategory(category, new NullProgressMonitor()); + ICategory result = marketplaceService.getCategory(category, new NullProgressMonitor()); assertNotNull(result); // FIXME: pending bug 302671 @@ -183,22 +182,21 @@ public class DefaultMarketplaceServiceTest { assertEquals(DefaultMarketplaceService.API_TAXONOMY_URI + "38,31", searchUrl); } - @SuppressWarnings("null") @Test public void search() throws CoreException { - List<Market> markets = marketplaceService.listMarkets(new NullProgressMonitor()); + List<? extends IMarket> markets = marketplaceService.listMarkets(new NullProgressMonitor()); assertTrue(!markets.isEmpty()); - Market toolsMarket = null; - for (Market market : markets) { + IMarket toolsMarket = null; + for (IMarket market : markets) { if ("Tools".equals(market.getName())) { toolsMarket = market; break; } } assertNotNull(toolsMarket); - Category mylynCategory = null; - for (Category category : toolsMarket.getCategory()) { + ICategory mylynCategory = null; + for (ICategory category : toolsMarket.getCategory()) { if ("Mylyn Connectors".equals(category.getName())) { mylynCategory = category; break; @@ -206,14 +204,14 @@ public class DefaultMarketplaceServiceTest { } assertNotNull(mylynCategory); - SearchResult result = marketplaceService.search(toolsMarket, mylynCategory, "WikiText", + ISearchResult result = marketplaceService.search(toolsMarket, mylynCategory, "WikiText", new NullProgressMonitor()); assertNotNull(result); assertNotNull(result.getNodes()); assertEquals(Integer.valueOf(1), result.getMatchCount()); assertEquals(1, result.getNodes().size()); - Node node = result.getNodes().get(0); + INode node = result.getNodes().get(0); assertTrue(node.getName().startsWith("Mylyn WikiText")); assertEquals("1065", node.getId()); @@ -221,13 +219,13 @@ public class DefaultMarketplaceServiceTest { @Test public void featured() throws CoreException { - SearchResult result = marketplaceService.featured(new NullProgressMonitor()); + ISearchResult result = marketplaceService.featured(new NullProgressMonitor()); assertSearchResultSanity(result); } @Test public void favorites() throws CoreException { - SearchResult result = marketplaceService.favorites(new NullProgressMonitor()); + ISearchResult result = marketplaceService.favorites(new NullProgressMonitor()); assertSearchResultSanity(result); } @@ -235,17 +233,17 @@ public class DefaultMarketplaceServiceTest { public void popular() throws CoreException { // NOTE: this test is failing until the following bug is fixed // bug 303275: REST API popular returns count of 6 with 10 nodes returned - SearchResult result = marketplaceService.popular(new NullProgressMonitor()); + ISearchResult result = marketplaceService.popular(new NullProgressMonitor()); assertSearchResultSanity(result); } @Test public void recent() throws CoreException { - SearchResult result = marketplaceService.recent(new NullProgressMonitor()); + ISearchResult result = marketplaceService.recent(new NullProgressMonitor()); assertSearchResultSanity(result); } - protected void assertSearchResultSanity(SearchResult result) { + protected void assertSearchResultSanity(ISearchResult result) { assertNotNull(result); assertNotNull(result.getNodes()); assertNotNull(result.getMatchCount()); @@ -253,7 +251,7 @@ public class DefaultMarketplaceServiceTest { assertTrue(result.getNodes().size() > 0); Set<String> ids = new HashSet<String>(); - for (Node node : result.getNodes()) { + for (INode node : result.getNodes()) { assertNotNull(node.getId()); assertTrue(ids.add(node.getId())); assertNotNull(node.getName()); diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/ServiceLocatorTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/ServiceLocatorTest.java new file mode 100644 index 00000000..1d6c4b74 --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/ServiceLocatorTest.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.tests.service; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class ServiceLocatorTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetMarketplaceServiceString() { + fail("Not yet implemented"); + } + + @Test + public void testGetCatalogService() { + fail("Not yet implemented"); + } + + @Test + public void testGetInstance() { + fail("Not yet implemented"); + } + +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/xml/UnmarshallerTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/xml/UnmarshallerTest.java index a5136ece..0bdb9398 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/xml/UnmarshallerTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/service/xml/UnmarshallerTest.java @@ -7,14 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.service.xml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.io.IOException; import java.io.InputStream; @@ -22,21 +19,22 @@ import java.io.InputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; -import org.eclipse.epp.internal.mpc.core.service.Catalog; -import org.eclipse.epp.internal.mpc.core.service.CatalogBranding; -import org.eclipse.epp.internal.mpc.core.service.Catalogs; -import org.eclipse.epp.internal.mpc.core.service.Categories; -import org.eclipse.epp.internal.mpc.core.service.Category; import org.eclipse.epp.internal.mpc.core.service.Favorites; import org.eclipse.epp.internal.mpc.core.service.Featured; -import org.eclipse.epp.internal.mpc.core.service.Market; import org.eclipse.epp.internal.mpc.core.service.Marketplace; import org.eclipse.epp.internal.mpc.core.service.News; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.core.service.Recent; import org.eclipse.epp.internal.mpc.core.service.Search; -import org.eclipse.epp.internal.mpc.core.service.Tag; import org.eclipse.epp.internal.mpc.core.service.xml.Unmarshaller; +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.eclipse.epp.mpc.core.model.ICatalogBranding; +import org.eclipse.epp.mpc.core.model.ICatalogs; +import org.eclipse.epp.mpc.core.model.ICategories; +import org.eclipse.epp.mpc.core.model.ICategory; +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.ITag; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -77,14 +75,14 @@ public class UnmarshallerTest { assertEquals(4, marketplace.getMarket().size()); - Market market = marketplace.getMarket().get(0); + IMarket market = marketplace.getMarket().get(0); assertEquals("31", market.getId()); assertEquals("Tools", market.getName()); assertEquals("http://www.eclipseplugincentral.net/category/markets/tools", market.getUrl()); assertEquals(36, market.getCategory().size()); - Category category = market.getCategory().get(10); + ICategory category = market.getCategory().get(10); assertEquals("24", category.getId()); assertEquals("IDE", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/24%2C31", category.getUrl()); @@ -100,14 +98,14 @@ public class UnmarshallerTest { assertEquals(1, marketplace.getCategory().size()); - Category category = marketplace.getCategory().get(0); + ICategory category = marketplace.getCategory().get(0); assertEquals("38,31", category.getId()); assertEquals("Mylyn Connectors", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/38%2C31", category.getUrl()); assertEquals(9, category.getNode().size()); - Node node = category.getNode().get(0); + INode node = category.getNode().get(0); // <node id="641" name="Tasktop Pro"> // <url>http://www.eclipseplugincentral.net/content/tasktop-pro</url> // <favorited>3</favorited> @@ -127,7 +125,7 @@ public class UnmarshallerTest { assertEquals(1, marketplace.getNode().size()); - Node node = marketplace.getNode().get(0); + INode node = marketplace.getNode().get(0); assertEquals("1065", node.getId()); assertEquals("Mylyn WikiText - Lightweight Markup Editing, Tools and Framework", node.getName()); assertEquals( @@ -140,7 +138,7 @@ public class UnmarshallerTest { assertNotNull(node.getCategories()); assertEquals(5, node.getCategories().getCategory().size()); - Category category = node.getCategories().getCategory().get(1); + ICategory category = node.getCategories().getCategory().get(1); // <category name='Tools'>/taxonomy/term/17</category> assertEquals("Tools", category.getName()); // FIXME category id. @@ -169,15 +167,15 @@ public class UnmarshallerTest { assertEquals(Integer.valueOf(6), featured.getCount()); assertEquals(6, featured.getNode().size()); - Node node = featured.getNode().get(0); + INode node = featured.getNode().get(0); assertEquals("248", node.getId()); assertEquals("eUML2 free edition", node.getName()); assertEquals("http://www.eclipseplugincentral.net/content/euml2-free-edition", node.getUrl()); assertEquals("resource", node.getType()); - Categories categories = node.getCategories(); + ICategories categories = node.getCategories(); assertNotNull(categories); assertEquals(1, categories.getCategory().size()); - Category category = categories.getCategory().get(0); + ICategory category = categories.getCategory().get(0); assertEquals("19", category.getId()); assertEquals("UML", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/19", category.getUrl()); @@ -215,16 +213,16 @@ public class UnmarshallerTest { search.getUrl()); assertEquals(Integer.valueOf(62), search.getCount()); assertEquals(7, search.getNode().size()); - Node node = search.getNode().get(0); + INode node = search.getNode().get(0); assertEquals("983", node.getId()); assertEquals("Run All Tests", node.getName()); assertEquals("http://www.eclipseplugincentral.net/content/run-all-tests", node.getUrl()); assertEquals("resource", node.getType()); - Categories categories = node.getCategories(); + ICategories categories = node.getCategories(); assertNotNull(categories); assertEquals(1, categories.getCategory().size()); - Category category = categories.getCategory().get(0); + ICategory category = categories.getCategory().get(0); assertEquals("16", category.getId()); assertEquals("Testing", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/16", category.getUrl()); @@ -246,7 +244,7 @@ public class UnmarshallerTest { assertEquals(Integer.valueOf(299995), node.getInstallsTotal()); assertEquals(Integer.valueOf(34540), node.getInstallsRecent()); - Node lastNode = search.getNode().get(search.getNode().size() - 1); + INode lastNode = search.getNode().get(search.getNode().size() - 1); assertEquals("1011", lastNode.getId()); assertEquals("JUnit Flux", lastNode.getName()); @@ -271,16 +269,16 @@ public class UnmarshallerTest { assertEquals(6, favorites.getNode().size()); - Node node = favorites.getNode().get(0); + INode node = favorites.getNode().get(0); assertEquals("206", node.getId()); assertEquals("Mylyn", node.getName()); assertEquals("http://www.eclipseplugincentral.net/content/mylyn", node.getUrl()); assertEquals("resource", node.getType()); - Categories categories = node.getCategories(); + ICategories categories = node.getCategories(); assertNotNull(categories); assertEquals(1, categories.getCategory().size()); - Category category = categories.getCategory().get(0); + ICategory category = categories.getCategory().get(0); assertEquals("18", category.getId()); assertEquals("UI", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/18", category.getUrl()); @@ -317,17 +315,17 @@ public class UnmarshallerTest { assertEquals(6, recent.getNode().size()); - Node node = recent.getNode().get(0); + INode node = recent.getNode().get(0); assertEquals("1091", node.getId()); assertEquals("API Demonstration Listing", node.getName()); assertEquals("http://www.eclipseplugincentral.net/content/api-demonstration-listing", node.getUrl()); assertEquals("resource", node.getType()); - Categories categories = node.getCategories(); + ICategories categories = node.getCategories(); assertNotNull(categories); assertEquals(6, categories.getCategory().size()); - Category category = categories.getCategory().get(0); + ICategory category = categories.getCategory().get(0); assertEquals("3", category.getId()); assertEquals("Database", category.getName()); assertEquals("http://www.eclipseplugincentral.net/taxonomy/term/3", category.getUrl()); @@ -376,11 +374,11 @@ public class UnmarshallerTest { public void tags() throws Exception { Object model = process("resources/node.xml"); Marketplace marketplace = (Marketplace) model; - Node node = marketplace.getNode().get(0); + INode node = marketplace.getNode().get(0); assertNotNull(node.getTags()); assertEquals(5, node.getCategories().getCategory().size()); - Tag tag = node.getTags().getTags().get(3); + ITag tag = node.getTags().getTags().get(3); assertEquals("mylyn", tag.getName()); assertEquals("88", tag.getId()); assertEquals("http://marketplace.eclipse.org/category/free-tagging/mylyn", tag.getUrl()); @@ -390,8 +388,8 @@ public class UnmarshallerTest { public void marketplaceCatalogs() throws IOException, SAXException { Object model = process("resources/catalogs.xml"); assertNotNull(model); - assertTrue(model instanceof Catalogs); - Catalogs catalogs = (Catalogs) model; + assertTrue(model instanceof ICatalogs); + ICatalogs catalogs = (ICatalogs) model; assertEquals(3, catalogs.getCatalogs().size()); @@ -406,7 +404,7 @@ public class UnmarshallerTest { // </wizard> // </catalog> - Catalog catalog = catalogs.getCatalogs().get(0); + ICatalog catalog = catalogs.getCatalogs().get(0); assertEquals("35656", catalog.getId()); assertEquals("Marketplace Catalog", catalog.getName()); assertEquals("http://marketplace.eclipse.org", catalog.getUrl()); @@ -415,7 +413,7 @@ public class UnmarshallerTest { assertEquals("http://marketplace.eclipse.org/sites/default/files/marketplace32.png", catalog.getImageUrl()); assertEquals("http://download.eclipse.org/releases/helios", catalog.getDependencyRepository()); - CatalogBranding branding = catalog.getBranding(); + ICatalogBranding branding = catalog.getBranding(); assertNotNull(branding); assertEquals("Eclipse Marketplace Catalog", branding.getWizardTitle()); assertEquals("http://marketplace.eclipse.org/sites/default/files/giant-rabbit2.jpg", branding.getWizardIcon()); @@ -426,7 +424,7 @@ public class UnmarshallerTest { assertFalse(branding.hasPopularTab()); assertTrue(branding.hasRecentTab()); - News news = catalog.getNews(); + INews news = catalog.getNews(); assertNotNull(news); assertEquals("http://marketplace.eclipse.org/news", news.getUrl()); assertEquals("News", news.getShortTitle()); diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/MarketplaceClientUiTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/MarketplaceClientUiTest.java index 45860c2c..d08e06b5 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/MarketplaceClientUiTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/MarketplaceClientUiTest.java @@ -7,11 +7,11 @@ * * Contributors: * Yatta Solutions - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.lang.reflect.InvocationTargetException; import java.net.ConnectException; @@ -25,12 +25,12 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.ServiceLocator; -import org.eclipse.epp.internal.mpc.core.service.CatalogService; import org.eclipse.epp.internal.mpc.core.service.DefaultCatalogService; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; +import org.eclipse.epp.mpc.core.service.ICatalogService; import org.eclipse.epp.mpc.ui.CatalogDescriptor; import org.eclipse.osgi.util.NLS; import org.junit.Test; @@ -96,7 +96,7 @@ public class MarketplaceClientUiTest { try { ServiceLocator.setInstance(new ServiceLocator() { @Override - public CatalogService getCatalogService() { + public ICatalogService getCatalogService() { return catalogService; } }); diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/CatalogDescriptorTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/CatalogDescriptorTest.java index edad2207..2ece9129 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/CatalogDescriptorTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/CatalogDescriptorTest.java @@ -7,11 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.catalog; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.net.URL; @@ -70,6 +70,6 @@ public class CatalogDescriptorTest { @Test(expected = IllegalArgumentException.class) public void testCopyCtorNull() { - new CatalogDescriptor(null); + new CatalogDescriptor((CatalogDescriptor) null); } } diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceCatalogTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceCatalogTest.java index 5498ea68..9f2a820a 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceCatalogTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceCatalogTest.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.catalog; @@ -31,6 +32,8 @@ import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem; +import org.eclipse.epp.mpc.core.model.IIus; +import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.epp.mpc.ui.CatalogDescriptor; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.junit.Before; @@ -38,20 +41,20 @@ import org.junit.Test; public class MarketplaceCatalogTest { - protected Set<Node> installedNodes; + protected Set<INode> installedNodes; - protected Set<Node> updateAvailable; + protected Set<INode> updateAvailable; - protected Set<Node> checkedForUpdate; + protected Set<INode> checkedForUpdate; protected List<Node> discoveryNodes; private MarketplaceCatalog catalog; @Before public void setUp() throws Exception { - installedNodes = new HashSet<Node>(); - updateAvailable = new HashSet<Node>(); - checkedForUpdate = new HashSet<Node>(); + installedNodes = new HashSet<INode>(); + updateAvailable = new HashSet<INode>(); + checkedForUpdate = new HashSet<INode>(); discoveryNodes = new ArrayList<Node>(); setupNodes(); @@ -107,8 +110,8 @@ public class MarketplaceCatalogTest { @Override protected Set<String> computeInstalledFeatures(IProgressMonitor monitor) { Set<String> installedIuIds = new HashSet<String>(); - for (Node node : installedNodes) { - Ius ius = node.getIus(); + for (INode node : installedNodes) { + IIus ius = node.getIus(); if (ius != null) { for (String iu : ius.getIu()) { installedIuIds.add(iu + ".feature.group"); diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceInfoTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceInfoTest.java index 7a22c2c1..a5ccb6c1 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceInfoTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/catalog/MarketplaceInfoTest.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.catalog; @@ -23,6 +24,7 @@ import org.eclipse.epp.internal.mpc.core.service.Ius; import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceInfo; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem; +import org.eclipse.epp.mpc.core.model.INode; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -88,7 +90,7 @@ public class MarketplaceInfoTest { Set<String> installedIus = new HashSet<String>(); installedIus.add("com.foo.bar"); - Set<Node> installedCatalogNodeIds = catalogRegistry.computeInstalledNodes(item.getMarketplaceUrl(), + Set<? extends INode> installedCatalogNodeIds = catalogRegistry.computeInstalledNodes(item.getMarketplaceUrl(), installedIus); assertNotNull(installedCatalogNodeIds); assertEquals(0, installedCatalogNodeIds.size()); @@ -138,7 +140,7 @@ public class MarketplaceInfoTest { @Test @SuppressWarnings("deprecation") public void computeInstalledLegacy() throws Exception { - Node node = item.getData(); + Node node = (Node) item.getData(); assertTrue(item.getInstallableUnits().size() > 1); assertEquals(0, catalogRegistry.getNodeKeyToIU().size()); diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceClientServiceTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceClientServiceTest.java new file mode 100644 index 00000000..90da3337 --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceClientServiceTest.java @@ -0,0 +1,289 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.tests.ui.wizard; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceClientService; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.service.QueryHelper; +import org.eclipse.epp.mpc.tests.ui.wizard.matcher.NodeMatcher; +import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration; +import org.eclipse.epp.mpc.ui.IMarketplaceClientService; +import org.eclipse.epp.mpc.ui.MarketplaceClient; +import org.eclipse.epp.mpc.ui.Operation; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.swtbot.swt.finder.SWTBot; +import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.results.ArrayResult; +import org.eclipse.swtbot.swt.finder.waits.Conditions; +import org.eclipse.swtbot.swt.finder.waits.ICondition; +import org.eclipse.swtbot.swt.finder.waits.WaitForObjectCondition; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotCombo; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTabItem; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.eclipse.swtbot.swt.finder.widgets.TimeoutException; +import org.eclipse.ui.PlatformUI; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +public class MarketplaceClientServiceTest { + + private SWTBot bot; + + private Display display; + + private IMarketplaceClientConfiguration config; + + private MarketplaceClientService service; + + @Before + public void setUp() { + service = new MarketplaceClientService(); + config = service.newConfiguration(); + display = PlatformUI.getWorkbench().getDisplay(); + } + + protected void initWizardBot() { + bot = new SWTBot(); + bot.waitUntil(Conditions.shellIsActive("Eclipse Marketplace")); + bot = bot.shell("Eclipse Marketplace").bot(); + SWTBotButton cancelButton = bot.button("Cancel"); + bot.waitUntil(Conditions.widgetIsEnabled(cancelButton), 30000); + } + + @After + public void tearDownBot() { + if (bot != null) { + String problem = null; + try { + //check if dialog is still open + SWTBotShell mpcShell = bot.shell("Eclipse Marketplace"); + try { + //check if any message dialogs are open + WaitForObjectCondition<Shell> subShellResult = Conditions.waitForShell(Matchers.any(Shell.class), + mpcShell.widget); + bot.waitUntil(subShellResult, 100, 60); + List<Shell> subShells = subShellResult.getAllMatches(); + for (Shell shell : subShells) { + SWTBotShell botShell = new SWTBotShell(shell); + + //children are unexpected, so let's cry foul... + if (problem == null) { + problem = "MPC wizard has open child dialog:"; + } + problem+="\n Shell(\""+botShell.getText()+"\")"; + + //kill message dialog + botShell.close(); + } + } catch (TimeoutException ex) { + } + //try killing it softly + try { + mpcShell.bot().button("Cancel").click(); + try { + ICondition shellCloses = Conditions.shellCloses(mpcShell); + bot.waitUntil(shellCloses); + return; + } catch (TimeoutException ex) { + } + } catch (TimeoutException ex) { + } + //now kill it hard - this is a last resort, because it can cause spurious errors in MPC jobs + mpcShell.close(); + } catch (TimeoutException e) { + //no MPC wizard found - maybe a bit strange, but so be it... + } finally { + if (problem != null) { + //something happened + fail(problem); + } + } + } + } + + @Test + public void testClientServiceAvailable() { + IMarketplaceClientService marketplaceClientService = MarketplaceClient.getMarketplaceClientService(); + assertNotNull(marketplaceClientService); + } + + @Test + public void testOpenDefault() throws Exception { + Display display = PlatformUI.getWorkbench().getDisplay(); + display.asyncExec(new Runnable() { + + public void run() { + service.open(config); + } + }); + + initWizardBot(); + checkSelectedTab("Search"); + } + + @Test + public void testOpenInstalled() throws Exception { + display.asyncExec(new Runnable() { + + public void run() { + service.openInstalled(config); + } + }); + + initWizardBot(); + checkSelectedTab("Installed"); + //We should get a message dialog here. Let's check that and close it. + bot.shell("No Extensions Found").close(); + } + + @Test + public void testOpenNodes() throws Exception { + display.asyncExec(new Runnable() { + + public void run() { + service.open(config, Collections.singleton(QueryHelper.nodeById("206"))); + } + }); + + initWizardBot(); + checkSelectedTab("Search"); + itemBot("206"); + } + + @Test + public void testOpenSearch() throws Exception { + final IMarket toolsMarket = QueryHelper.marketByName("Tools"); + final ICategory mylynCategory = QueryHelper.categoryByName("Mylyn Connectors"); + + display.asyncExec(new Runnable() { + + public void run() { + service.openSearch(config, toolsMarket, mylynCategory, "WikiText"); + } + }); + + initWizardBot(); + checkSelectedTab("Search"); + + SWTBotCombo marketCombo = bot.comboBox(0); + SWTBotCombo categoryCombo = bot.comboBox(1); + assertEquals("Tools", marketCombo.getText()); + assertEquals("Mylyn Connectors", categoryCombo.getText()); + + SWTBotText searchText = bot.text(0); + assertEquals("WikiText", searchText.getText()); + + itemBot(NodeMatcher.withNameRegex(".*WikiText.*")); + + } + + @Test + public void testOpenWithSelection() throws Exception { + config.setInitialOperations(Collections.singletonMap("206", Operation.INSTALL)); + + display.asyncExec(new Runnable() { + + public void run() { + service.open(config); + } + }); + + initWizardBot(); + checkSelectedTab("Search"); + SWTBot itemBot = itemBot("206"); + itemBot.button("Install Pending").isEnabled(); + bot.button("Install Now >").isEnabled(); + } + + @Test + public void testOpenSelected() throws Exception { + config.setInitialOperations(Collections.singletonMap("206", Operation.INSTALL)); + + display.asyncExec(new Runnable() { + + public void run() { + service.openSelected(config); + } + }); + + initWizardBot(); + checkSelectedTab("Search"); + SWTBot itemBot = itemBot("206"); + itemBot.button("Install Pending").isEnabled(); + bot.button("Install Now >").isEnabled(); + } + + @Test + public void testOpenProvisioning() throws Exception { + config.setInitialOperations(Collections.singletonMap("206", Operation.INSTALL)); + + display.asyncExec(new Runnable() { + + public void run() { + service.openProvisioning(config); + } + }); + + initWizardBot(); + + //make sure we are on the second page and can proceed + bot.label("Confirm Selected Features"); + bot.button("< Install More").isEnabled(); + bot.button("Confirm >").isEnabled(); + + //make sure we have one top-level item with multiple children + SWTBotTreeItem[] nodeItems = bot.tree().getAllItems(); + assertEquals(1, nodeItems.length); + SWTBotTreeItem[] featureItems = nodeItems[0].getItems(); + assertTrue(featureItems.length > 0); + } + + protected SWTBot itemBot(NodeMatcher<? extends Widget> matcher) { + List<? extends Widget> controls = bot.getFinder().findControls(matcher); + assertThat(controls.size(), greaterThanOrEqualTo(1)); + Widget firstItem = controls.get(0); + return new SWTBot(firstItem); + } + + protected SWTBot itemBot(String id) { + return itemBot(NodeMatcher.withId(id)); + } + + protected void checkSelectedTab(String tabLabel) { + SWTBotTabItem searchTab = bot.tabItem(tabLabel); + final TabItem tab = searchTab.widget; + TabItem[] selection = UIThreadRunnable.syncExec(new ArrayResult<TabItem>() { + + public TabItem[] run() { + return tab.getParent().getSelection(); + } + }); + assertEquals(1, selection.length); + assertSame(tab, selection[0]); + } +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceDiscoveryStrategyTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceDiscoveryStrategyTest.java index 178379ff..3d535414 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceDiscoveryStrategyTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceDiscoveryStrategyTest.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.wizard; @@ -17,15 +18,16 @@ import java.net.URL; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.epp.internal.mpc.core.service.Category; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.MarketplaceService; import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.core.service.SearchResult; import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; import org.eclipse.epp.mpc.ui.CatalogDescriptor; import org.junit.After; import org.junit.Assert; @@ -53,10 +55,10 @@ public class MarketplaceDiscoveryStrategyTest { catalog = new MarketplaceCatalog(); } - private void setupCatalog(final MarketplaceService marketplaceService) { + private void setupCatalog(final IMarketplaceService marketplaceService) { discoveryStrategy = new MarketplaceDiscoveryStrategy(catalogDescriptor) { @Override - public MarketplaceService createMarketplaceService() { + public IMarketplaceService createMarketplaceService() { return marketplaceService; } }; @@ -72,16 +74,16 @@ public class MarketplaceDiscoveryStrategyTest { @Test public void testSearchByNodeUrl() throws Exception { - final Node[] testNode = new Node[1]; - final MarketplaceService marketplaceService = new DefaultMarketplaceService(catalogUrl) { + final INode[] testNode = new INode[1]; + final IMarketplaceService marketplaceService = new DefaultMarketplaceService(catalogUrl) { @Override - public Node getNode(Node node, IProgressMonitor monitor) throws CoreException { + public Node getNode(INode node, IProgressMonitor monitor) throws CoreException { testNode[0] = node; - return node; + return (Node) node; } @Override - public SearchResult search(Market market, Category category, String queryText, IProgressMonitor monitor) + public SearchResult search(IMarket market, ICategory category, String queryText, IProgressMonitor monitor) throws CoreException { Assert.fail("Unexpected invocation"); return null;//dead code diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceUrlHandlerTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceUrlHandlerTest.java index b34a50f5..a7fd3210 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceUrlHandlerTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/MarketplaceUrlHandlerTest.java @@ -7,29 +7,26 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.wizard; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.net.URL; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; -import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceUrlHandler; -import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceUrlHandler.SolutionInstallationInfo; +import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler; +import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test {@link MarketplaceUrlHandler} - * + * * @author Benjamin Muskalla */ public class MarketplaceUrlHandlerTest { @@ -91,10 +88,10 @@ public class MarketplaceUrlHandlerTest { @Test public void testNodeUrls() throws Exception { - final Node[] testNode = new Node[1]; + final INode[] testNode = new INode[1]; MarketplaceUrlHandler handler = new MarketplaceUrlHandler() { @Override - protected boolean handleNode(CatalogDescriptor descriptor, String url, Node node) { + protected boolean handleNode(CatalogDescriptor descriptor, String url, INode node) { testNode[0] = node; return true; } diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/SelectionModelStateSerializerTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/SelectionModelStateSerializerTest.java index 010a80e3..2b267645 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/SelectionModelStateSerializerTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/SelectionModelStateSerializerTest.java @@ -7,13 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.ui.wizard; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.net.URL; import java.util.Collections; @@ -24,14 +22,14 @@ import java.util.Set; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.MarketplaceService; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; import org.eclipse.epp.internal.mpc.ui.wizards.InstallProfile; -import org.eclipse.epp.internal.mpc.ui.wizards.Operation; import org.eclipse.epp.internal.mpc.ui.wizards.SelectionModel; import org.eclipse.epp.internal.mpc.ui.wizards.SelectionModelStateSerializer; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.junit.After; import org.junit.Before; @@ -54,7 +52,7 @@ public class SelectionModelStateSerializerTest { "Eclipse.org Marketplace"); discoveryStrategy = new MarketplaceDiscoveryStrategy(catalogDescriptor) { @Override - public MarketplaceService createMarketplaceService() { + public IMarketplaceService createMarketplaceService() { DefaultMarketplaceService marketplaceService = new DefaultMarketplaceService(catalogDescriptor.getUrl()); Map<String, String> requestMetaParameters = new HashMap<String, String>(); requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_CLIENT, MarketplaceClientCore.BUNDLE_ID); @@ -97,15 +95,15 @@ public class SelectionModelStateSerializerTest { selectionModel.clear(); - assertTrue(selectionModel.getItemToOperation().isEmpty()); + assertTrue(selectionModel.getItemToSelectedOperation().isEmpty()); assertFalse(selectionModel.computeProvisioningOperationViable()); - serializer.deserialize(new NullProgressMonitor(), state); + serializer.deserialize(state, new NullProgressMonitor()); - assertEquals(2, selectionModel.getItemToOperation().size()); + assertEquals(2, selectionModel.getItemToSelectedOperation().size()); assertTrue(selectionModel.computeProvisioningOperationViable()); - Map<CatalogItem, Operation> itemToOperation = selectionModel.getItemToOperation(); + Map<CatalogItem, Operation> itemToOperation = selectionModel.getItemToSelectedOperation(); assertEquals(Operation.INSTALL, itemToOperation.get(firstItem)); assertEquals(Operation.INSTALL, itemToOperation.get(secondItem)); } diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/matcher/NodeMatcher.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/matcher/NodeMatcher.java new file mode 100644 index 00000000..ed1767aa --- /dev/null +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/ui/wizard/matcher/NodeMatcher.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.tests.ui.wizard.matcher; + +import java.util.regex.Pattern; + +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.swtbot.swt.finder.matchers.AbstractMatcher; +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +public class NodeMatcher<T extends Widget> extends AbstractMatcher<T> { + + private final Matcher<INode> matcher; + + NodeMatcher(Matcher<INode> matcher) { + this.matcher = matcher; + } + + @Override + protected boolean doMatch(Object obj) { + if (obj instanceof Widget) { + Widget w = (Widget) obj; + Object data = w.getData(); + INode node = null; + if (data instanceof CatalogItem) { + data = ((CatalogItem) data).getData(); + } + if (data instanceof INode) { + node = (INode) data; + } + return node != null && matcher.matches(node); + } + return false; + } + + public void describeTo(Description description) { + description.appendText("with node matching "); //$NON-NLS-1$ + matcher.describeTo(description); + } + + @Factory + public static <T extends Widget> NodeMatcher<T> withNode(Matcher<INode> matcher) { + return new NodeMatcher<T>(matcher); + } + + @Factory + public static <T extends Widget> NodeMatcher<T> withId(String id) { + return withNode(new NodeValueMatcher<String>("id", id) { + + @Override + protected String getValue(INode item) { + return item.getId(); + } + }); + } + + @Factory + public static <T extends Widget> NodeMatcher<T> withUrl(String url) { + return withNode(new NodeValueMatcher<String>("url", url) { + + @Override + protected String getValue(INode item) { + return item.getUrl(); + } + }); + } + + @Factory + public static <T extends Widget> NodeMatcher<T> withName(String name) { + return withNode(new NodeValueMatcher<String>("name", name) { + + @Override + protected String getValue(INode item) { + return item.getName(); + } + }); + } + + @Factory + public static <T extends Widget> NodeMatcher<T> withNameRegex(String name) { + return withNode(new NodeValueMatcher<String>("name", name) { + private final Pattern pattern = Pattern.compile(expected); + @Override + protected boolean doMatch(String expected, String actual) { + return pattern.matcher(actual).matches(); + } + + @Override + protected String getValue(INode item) { + return item.getName(); + } + }); + } + + private static abstract class NodeValueMatcher<T> extends AbstractMatcher<INode> { + final String valueName; + + final T expected; + + public NodeValueMatcher(String valueName, T expected) { + super(); + this.valueName = valueName; + this.expected = expected; + } + + public void describeTo(Description description) { + description.appendText(valueName).appendText(" "); + description.appendValue(expected); + } + + @Override + protected boolean doMatch(Object item) { + return item instanceof INode && doMatch(expected, getValue((INode) item)); + } + + protected boolean doMatch(T expected, T actual) { + return expected.equals(actual); + } + + protected abstract T getValue(INode item); + } +} diff --git a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/util/TransportFactoryTest.java b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/util/TransportFactoryTest.java index 96423ed3..6ddfa122 100644 --- a/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/util/TransportFactoryTest.java +++ b/org.eclipse.epp.mpc.tests/src/org/eclipse/epp/mpc/tests/util/TransportFactoryTest.java @@ -7,33 +7,75 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.tests.util; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import java.io.InputStream; import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.epp.internal.mpc.core.util.ITransport; +import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; import org.eclipse.epp.internal.mpc.core.util.TransportFactory; +import org.eclipse.epp.mpc.core.service.ITransport; +import org.eclipse.epp.mpc.core.service.ITransportFactory; +import org.eclipse.epp.mpc.core.service.ServiceHelper; +import org.hamcrest.CoreMatchers; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; @RunWith(BlockJUnit4ClassRunner.class) public class TransportFactoryTest { @Test + public void testRegisteredFactories() throws Exception { + BundleContext context = MarketplaceClientCorePlugin.getBundle().getBundleContext(); + Collection<ServiceReference<ITransportFactory>> serviceReferences = context.getServiceReferences( + ITransportFactory.class, null); + assertFalse(serviceReferences.isEmpty()); + List<Class<?>> registeredFactories; + registeredFactories = new ArrayList<Class<?>>(); + for (ServiceReference<ITransportFactory> serviceReference : serviceReferences) { + try { + ITransportFactory service = context.getService(serviceReference); + assertNotNull(service); + registeredFactories.add(service.getClass()); + } finally { + context.ungetService(serviceReference); + } + } + + List<ITransportFactory> legacyFactories = TransportFactory.listAvailableFactories(); + for (ITransportFactory factory : legacyFactories) { + assertThat(registeredFactories, CoreMatchers.hasItem(factory.getClass())); + } + } + + @Test public void testTansportFactoryInstance() { - ITransport transport = TransportFactory.instance().getTransport(); + ITransport transport = TransportFactory.createTransport(); + assertNotNull(transport); + } + + @Test + @SuppressWarnings("deprecation") + public void testLegacyTansportFactoryInstance() { + TransportFactory instance = TransportFactory.instance(); + org.eclipse.epp.internal.mpc.core.util.ITransport transport = instance.getTransport(); assertNotNull(transport); } @Test public void testStream() throws Exception { - ITransport transport = TransportFactory.instance().getTransport(); + ITransport transport = ServiceHelper.getTransportFactory().getTransport(); URI uri = new URI("http://www.eclipse.org/index.php"); InputStream stream = transport.stream(uri, new NullProgressMonitor()); assertNotNull(stream); diff --git a/org.eclipse.epp.mpc.ui/.project b/org.eclipse.epp.mpc.ui/.project index 85d0cd8a..930dbe31 100644 --- a/org.eclipse.epp.mpc.ui/.project +++ b/org.eclipse.epp.mpc.ui/.project @@ -25,6 +25,11 @@ <arguments> </arguments> </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ds.core.builder</name> + <arguments> + </arguments> + </buildCommand> </buildSpec> <natures> <nature>org.eclipse.pde.PluginNature</nature> diff --git a/org.eclipse.epp.mpc.ui/.settings/.api_filters b/org.eclipse.epp.mpc.ui/.settings/.api_filters new file mode 100644 index 00000000..55115751 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/.settings/.api_filters @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<component id="org.eclipse.epp.mpc.ui" version="2"> + <resource path="src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java" type="org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy"> + <filter comment="Report install error as part of the wizard's install operation" id="640712815"> + <message_arguments> + <message_argument value="IMarketplaceService"/> + <message_argument value="MarketplaceDiscoveryStrategy"/> + <message_argument value="reportInstallError(IStatus, Set<? extends INode>, Set<String>, String, IProgressMonitor)"/> + </message_arguments> + </filter> + </resource> + <resource path="src/org/eclipse/epp/internal/mpc/ui/wizards/ProvisioningJobListener.java" type="org.eclipse.epp.internal.mpc.ui.wizards.ProvisioningJobListener"> + <filter comment="report install success as part of the wizard's install operation" id="640712815"> + <message_arguments> + <message_argument value="IMarketplaceService"/> + <message_argument value="ProvisioningJobListener"/> + <message_argument value="reportInstallSuccess(INode, IProgressMonitor)"/> + </message_arguments> + </filter> + </resource> +</component> diff --git a/org.eclipse.epp.mpc.ui/META-INF/MANIFEST.MF b/org.eclipse.epp.mpc.ui/META-INF/MANIFEST.MF index 4c1894ad..de142a49 100644 --- a/org.eclipse.epp.mpc.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.epp.mpc.ui/META-INF/MANIFEST.MF @@ -16,10 +16,12 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.6.0", org.eclipse.equinox.p2.core;bundle-version="1.0.4", org.eclipse.equinox.p2.ui;bundle-version="1.0.4", org.eclipse.equinox.p2.metadata;bundle-version="1.0.0", - org.eclipse.equinox.p2.operations, + org.eclipse.equinox.p2.operations;bundle-version="2.3.0", org.eclipse.equinox.p2.repository;bundle-version="1.0.0", org.eclipse.equinox.p2.engine, - org.eclipse.equinox.p2.director + org.eclipse.equinox.p2.director, + org.eclipse.osgi.services;bundle-version="3.4.0", + org.eclipse.equinox.ds;bundle-version="1.4.200" Export-Package: org.eclipse.epp.internal.mpc.ui;x-internal:=true, org.eclipse.epp.internal.mpc.ui.actions;x-internal:=true, org.eclipse.epp.internal.mpc.ui.catalog;x-internal:=true, @@ -30,3 +32,4 @@ Export-Package: org.eclipse.epp.internal.mpc.ui;x-internal:=true, org.eclipse.epp.mpc.ui Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin +Service-Component: OSGI-INF/services/*.xml diff --git a/org.eclipse.epp.mpc.ui/OSGI-INF/services/marketplace-client.xml b/org.eclipse.epp.mpc.ui/OSGI-INF/services/marketplace-client.xml new file mode 100644 index 00000000..232fe0aa --- /dev/null +++ b/org.eclipse.epp.mpc.ui/OSGI-INF/services/marketplace-client.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.ui.marketplace-client">
+ <implementation class="org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceClientService"/>
+ <service>
+ <provide interface="org.eclipse.epp.mpc.ui.IMarketplaceClientService"/>
+ </service> +</scr:component>
diff --git a/org.eclipse.epp.mpc.ui/build.properties b/org.eclipse.epp.mpc.ui/build.properties index 0baae269..2190a209 100644 --- a/org.eclipse.epp.mpc.ui/build.properties +++ b/org.eclipse.epp.mpc.ui/build.properties @@ -7,6 +7,7 @@ # # Contributors: # The Eclipse Foundation - initial API and implementation +# Yatta Solutions - bug 432803: public API ############################################################################### source.. = src/ output.. = bin/ @@ -19,6 +20,7 @@ bin.includes = META-INF/,\ about.ini,\ about.html,\ OSGI-INF/l10n/,\ + OSGI-INF/services/,\ .options src.includes = schema/,\ about.html diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/CatalogRegistry.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/CatalogRegistry.java index e274c7f4..18ba5c2d 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/CatalogRegistry.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/CatalogRegistry.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui; @@ -16,8 +17,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import org.eclipse.epp.internal.mpc.core.service.CatalogBranding; -import org.eclipse.epp.internal.mpc.core.service.News; +import org.eclipse.epp.mpc.core.model.ICatalogBranding; +import org.eclipse.epp.mpc.core.model.INews; import org.eclipse.epp.mpc.ui.CatalogDescriptor; /** @@ -37,9 +38,7 @@ public class CatalogRegistry { private final List<CatalogDescriptor> catalogDescriptors = new CopyOnWriteArrayList<CatalogDescriptor>(); - private final Map<CatalogDescriptor, CatalogBranding> catalogBrandings = new HashMap<CatalogDescriptor, CatalogBranding>(); - - private final Map<CatalogDescriptor, News> catalogNews = new HashMap<CatalogDescriptor, News>(); + private final Map<CatalogDescriptor, INews> catalogNews = new HashMap<CatalogDescriptor, INews>(); public CatalogRegistry() { catalogDescriptors.addAll(new CatalogExtensionPointReader().getCatalogDescriptors()); @@ -51,7 +50,6 @@ public class CatalogRegistry { public void unregister(CatalogDescriptor catalogDescriptor) { catalogDescriptors.remove(catalogDescriptor); - catalogBrandings.remove(catalogDescriptor); catalogNews.remove(catalogDescriptor); } @@ -59,21 +57,31 @@ public class CatalogRegistry { return Collections.unmodifiableList(catalogDescriptors); } - // TODO: remove and integrate into CatalogDescriptor once we are not in API freeze - public void addCatalogBranding(CatalogDescriptor descriptor, CatalogBranding branding) { - catalogBrandings.put(descriptor, branding); + /** + * @deprecated use {@link CatalogDescriptor#setCatalogBranding(ICatalogBranding) + * descriptor.setCatalogBranding(branding)} + */ + @Deprecated + public void addCatalogBranding(CatalogDescriptor descriptor, ICatalogBranding branding) { + if (descriptor != null) { + descriptor.setCatalogBranding(branding); + } } - public CatalogBranding getCatalogBranding(CatalogDescriptor descriptor) { - return catalogBrandings.get(descriptor); + /** + * @deprecated use {@link CatalogDescriptor#getCatalogBranding() descriptor.getCatalogBranding()} + */ + @Deprecated + public ICatalogBranding getCatalogBranding(CatalogDescriptor descriptor) { + return descriptor == null ? null : descriptor.getCatalogBranding(); } // manage the predefined news configuration here, since that isn't supposed to become API - public void addCatalogNews(CatalogDescriptor descriptor, News news) { + public void addCatalogNews(CatalogDescriptor descriptor, INews news) { catalogNews.put(descriptor, news); } - public News getCatalogNews(CatalogDescriptor descriptor) { + public INews getCatalogNews(CatalogDescriptor descriptor) { return catalogNews.get(descriptor); } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUi.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUi.java index d72581c7..2ce30963 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUi.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUi.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - error handling (bug 374105) + * Yatta Solutions - error handling (bug 374105), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui; @@ -19,7 +19,6 @@ import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -154,9 +153,9 @@ public class MarketplaceClientUi { public static Map<String, IInstallableUnit> computeInstalledIUsById(IProgressMonitor monitor) { Map<String, IInstallableUnit> iUs = new HashMap<String, IInstallableUnit>(); BundleContext bundleContext = MarketplaceClientUi.getBundleContext(); - ServiceReference serviceReference = bundleContext.getServiceReference(IProvisioningAgent.SERVICE_NAME); + ServiceReference<IProvisioningAgent> serviceReference = bundleContext.getServiceReference(IProvisioningAgent.class); if (serviceReference != null) { - IProvisioningAgent agent = (IProvisioningAgent) bundleContext.getService(serviceReference); + IProvisioningAgent agent = bundleContext.getService(serviceReference); try { IProfileRegistry profileRegistry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME); if (profileRegistry != null) { @@ -164,8 +163,7 @@ public class MarketplaceClientUi { if (profile != null) { IQueryResult<IInstallableUnit> result = profile.available(QueryUtil.createIUGroupQuery(), monitor); - for (Iterator<IInstallableUnit> it = result.iterator(); it.hasNext();) { - IInstallableUnit unit = it.next(); + for (IInstallableUnit unit : result) { iUs.put(unit.getId(), unit); } } @@ -181,9 +179,9 @@ public class MarketplaceClientUi { Set<String> features = new HashSet<String>(); BundleContext bundleContext = MarketplaceClientUi.getBundleContext(); - ServiceReference serviceReference = bundleContext.getServiceReference(IProvisioningAgent.SERVICE_NAME); + ServiceReference<IProvisioningAgent> serviceReference = bundleContext.getServiceReference(IProvisioningAgent.class); if (serviceReference != null) { - IProvisioningAgent agent = (IProvisioningAgent) bundleContext.getService(serviceReference); + IProvisioningAgent agent = bundleContext.getService(serviceReference); try { IProfileRegistry profileRegistry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME); if (profileRegistry != null) { @@ -191,8 +189,7 @@ public class MarketplaceClientUi { if (profile != null) { IQueryResult<IInstallableUnit> result = profile.available(QueryUtil.createIUGroupQuery(), monitor); - for (Iterator<IInstallableUnit> it = result.iterator(); it.hasNext();) { - IInstallableUnit unit = it.next(); + for (IInstallableUnit unit : result) { features.add(unit.getId()); } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java index 089963db..37c9ccf8 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/MarketplaceClientUiPlugin.java @@ -7,16 +7,19 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui; +import org.eclipse.epp.mpc.ui.IMarketplaceClientService; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; /** * bundle activator. Prefer {@link MarketplaceClientUi} where possible. - * + * * @author David Green */ public class MarketplaceClientUiPlugin extends AbstractUIPlugin { @@ -49,6 +52,8 @@ public class MarketplaceClientUiPlugin extends AbstractUIPlugin { private static MarketplaceClientUiPlugin instance; + private ServiceTracker<IMarketplaceClientService, IMarketplaceClientService> clientServiceTracker; + public MarketplaceClientUiPlugin() { } @@ -56,10 +61,15 @@ public class MarketplaceClientUiPlugin extends AbstractUIPlugin { public void start(BundleContext context) throws Exception { instance = this; super.start(context); + clientServiceTracker = new ServiceTracker<IMarketplaceClientService, IMarketplaceClientService>(context, + IMarketplaceClientService.class, null); + clientServiceTracker.open(); } @Override public void stop(BundleContext context) throws Exception { + clientServiceTracker.close(); + clientServiceTracker = null; super.stop(context); instance = null; } @@ -87,4 +97,8 @@ public class MarketplaceClientUiPlugin extends AbstractUIPlugin { imageRegistry.put(ITEM_ICON_SHARE, imageDescriptorFromPlugin(getBundle().getSymbolicName(), "icons/share.png")); //$NON-NLS-1$ return imageRegistry; } + + public IMarketplaceClientService getClientService() { + return clientServiceTracker == null ? null : clientServiceTracker.getService(); + } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/AbstractResourceRunnable.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/AbstractResourceRunnable.java index 2aafe699..0e46c2f3 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/AbstractResourceRunnable.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/AbstractResourceRunnable.java @@ -29,7 +29,7 @@ import org.eclipse.osgi.util.NLS; /** * A runnable that downloads a resource from an URL - * + * * @author David Green */ abstract class AbstractResourceRunnable implements IRunnableWithProgress, Callable<Object> { @@ -61,7 +61,7 @@ abstract class AbstractResourceRunnable implements IRunnableWithProgress, Callab try { URL imageUrl = new URL(resourceUrl); - InputStream in = TransportFactory.instance().getTransport().stream(imageUrl.toURI(), monitor); + InputStream in = TransportFactory.createTransport().stream(imageUrl.toURI(), monitor); try { resourceProvider.putResource(resourceUrl, in); } finally { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java index 2687d8a8..2037f12f 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalog.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - error handling (bug 374105), news (bug 401721) + * Yatta Solutions - error handling (bug 374105), news (bug 401721), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; @@ -28,12 +28,12 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.epp.internal.mpc.core.service.Category; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.News; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.util.ConcurrentTaskManager; +import org.eclipse.epp.mpc.core.model.ICategory; +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.equinox.internal.p2.discovery.AbstractDiscoveryStrategy; import org.eclipse.equinox.internal.p2.discovery.Catalog; import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore; @@ -61,13 +61,13 @@ public class MarketplaceCatalog extends Catalog { private final Map<String, Boolean> updateAvailableByNodeId = new HashMap<String, Boolean>(); - private News news; + private INews news; private interface DiscoveryOperation { public void run(MarketplaceDiscoveryStrategy strategy, IProgressMonitor monitor) throws CoreException; } - public IStatus performQuery(final Market market, final Category category, final String queryText, + public IStatus performQuery(final IMarket market, final ICategory category, final String queryText, IProgressMonitor monitor) { return performDiscovery(new DiscoveryOperation() { public void run(MarketplaceDiscoveryStrategy strategy, IProgressMonitor monitor) throws CoreException { @@ -92,7 +92,7 @@ public class MarketplaceCatalog extends Catalog { }, monitor); } - public IStatus featured(IProgressMonitor monitor, final Market market, final Category category) { + public IStatus featured(IProgressMonitor monitor, final IMarket market, final ICategory category) { return performDiscovery(new DiscoveryOperation() { public void run(MarketplaceDiscoveryStrategy strategy, IProgressMonitor monitor) throws CoreException { strategy.featured(monitor, market, category); @@ -134,7 +134,7 @@ public class MarketplaceCatalog extends Catalog { * the nodes to retrieve * @return */ - public IStatus performNodeQuery(IProgressMonitor monitor, final Set<Node> nodes) { + public IStatus performNodeQuery(IProgressMonitor monitor, final Set<? extends INode> nodes) { return performDiscovery(new DiscoveryOperation() { public void run(MarketplaceDiscoveryStrategy strategy, IProgressMonitor monitor) throws CoreException { strategy.performNodeQuery(monitor, nodes); @@ -182,7 +182,7 @@ public class MarketplaceCatalog extends Catalog { Map<URI, List<MarketplaceNodeCatalogItem>> installedCatalogItemsByUpdateUri = new HashMap<URI, List<MarketplaceNodeCatalogItem>>(); for (MarketplaceNodeCatalogItem catalogItem : updateCheckNeeded) { - Node node = catalogItem.getData(); + INode node = catalogItem.getData(); try { String updateurl = node.getUpdateurl(); if (updateurl == null) { @@ -387,7 +387,7 @@ public class MarketplaceCatalog extends Catalog { throw new IllegalStateException(); } - News news = null; + INews news = null; MultiStatus status = new MultiStatus(MarketplaceClientUi.BUNDLE_ID, 0, Messages.MarketplaceCatalog_queryFailed, null); @@ -450,11 +450,11 @@ public class MarketplaceCatalog extends Catalog { } } - public News getNews() { + public INews getNews() { return news; } - public void setNews(News news) { + public void setNews(INews news) { this.news = news; } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalogSource.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalogSource.java index 813e90ca..a4a6bec5 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalogSource.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCatalogSource.java @@ -7,13 +7,14 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; import java.io.IOException; import java.net.URL; -import org.eclipse.epp.internal.mpc.core.service.MarketplaceService; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource; /** @@ -21,11 +22,11 @@ import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource; */ public class MarketplaceCatalogSource extends AbstractCatalogSource { - private final MarketplaceService marketplaceService; + private final IMarketplaceService marketplaceService; private ResourceProvider resourceProvider; - public MarketplaceCatalogSource(MarketplaceService marketplaceService) { + public MarketplaceCatalogSource(IMarketplaceService marketplaceService) { this.marketplaceService = marketplaceService; try { resourceProvider = new ResourceProvider(); @@ -48,7 +49,7 @@ public class MarketplaceCatalogSource extends AbstractCatalogSource { return resourceProvider; } - public MarketplaceService getMarketplaceService() { + public IMarketplaceService getMarketplaceService() { return marketplaceService; } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCategory.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCategory.java index bcda0ce4..6c06c076 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCategory.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceCategory.java @@ -7,13 +7,14 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; import java.util.List; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.SearchResult; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.ISearchResult; import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory; /** @@ -25,17 +26,17 @@ public class MarketplaceCategory extends CatalogCategory { FEATURED, POPULAR, INSTALLED, RECENT, QUERY } - private List<Market> markets; + private List<? extends IMarket> markets; private Contents contents; private int matchCount; - public void setMarkets(List<Market> markets) { + public void setMarkets(List<? extends IMarket> markets) { this.markets = markets; } - public List<Market> getMarkets() { + public List<? extends IMarket> getMarkets() { return markets; } @@ -54,7 +55,7 @@ public class MarketplaceCategory extends CatalogCategory { /** * Indicate how many solutions matched the query, which may not be the same as the number of nodes returned. * - * @see SearchResult#getMatchCount() + * @see ISearchResult#getMatchCount() */ public int getMatchCount() { return matchCount; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java index 2606a542..cc2ff55c 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceDiscoveryStrategy.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - bug 314936, bug 398200 + * Yatta Solutions - bug 314936, bug 398200, public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; @@ -15,38 +15,39 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProduct; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; -import org.eclipse.epp.internal.mpc.core.service.CachingMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Categories; -import org.eclipse.epp.internal.mpc.core.service.Category; -import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Ius; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.MarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.News; +import org.eclipse.epp.internal.mpc.core.ServiceLocator; +import org.eclipse.epp.internal.mpc.core.service.Identifiable; import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.core.service.SearchResult; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory.Contents; import org.eclipse.epp.internal.mpc.ui.util.ConcurrentTaskManager; -import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceUrlHandler; +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.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.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; @@ -55,7 +56,6 @@ 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.osgi.util.NLS; -import org.osgi.framework.Bundle; /** * @author David Green @@ -68,7 +68,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { protected final CatalogDescriptor catalogDescriptor; - private final MarketplaceService marketplaceService; + private final IMarketplaceService marketplaceService; private MarketplaceCatalogSource source; @@ -81,46 +81,30 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { throw new IllegalArgumentException(); } this.catalogDescriptor = catalogDescriptor; - marketplaceService = createMarketplaceService(); + marketplaceService = createMarketplaceService();//use deprecated method in case someone has overridden it source = new MarketplaceCatalogSource(marketplaceService); marketplaceInfo = MarketplaceInfo.getInstance(); } - public MarketplaceService createMarketplaceService() { - DefaultMarketplaceService service = new DefaultMarketplaceService(this.catalogDescriptor.getUrl()); - Map<String, String> requestMetaParameters = computeDefaultRequestMetaParameters(); - service.setRequestMetaParameters(requestMetaParameters); - return new CachingMarketplaceService(service); + /** + * @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() { - Map<String, String> requestMetaParameters = new HashMap<String, String>(); - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_CLIENT, MarketplaceClientCore.BUNDLE_ID); - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_OS, Platform.getOS()); - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_WS, Platform.getWS()); - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_NL, Platform.getNL()); - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_JAVA_VERSION, System.getProperty("java.version")); //$NON-NLS-1$ - IProduct product = Platform.getProduct(); - if (product != null) { - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PRODUCT, product.getId()); - Bundle productBundle = product.getDefiningBundle(); - if (productBundle != null) { - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION, - productBundle.getVersion().toString()); - } - } - Bundle runtimeBundle = Platform.getBundle("org.eclipse.core.runtime"); //$NON-NLS-1$ - if (runtimeBundle != null) { - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION, runtimeBundle.getVersion() - .toString()); - } - // also send the platform version to distinguish between 3.x and 4.x platforms using the same runtime - Bundle platformBundle = Platform.getBundle("org.eclipse.platform"); //$NON-NLS-1$ - if (platformBundle != null) { - requestMetaParameters.put(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION, - platformBundle.getVersion().toString()); - } - return requestMetaParameters; + return ServiceLocator.computeDefaultRequestMetaParameters(); } @Override @@ -149,7 +133,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { catalogCategory.setContents(Contents.FEATURED); - SearchResult featured = marketplaceService.featured(new SubProgressMonitor(monitor, workSegment)); + ISearchResult featured = marketplaceService.featured(new SubProgressMonitor(monitor, workSegment)); handleSearchResult(catalogCategory, featured, new SubProgressMonitor(monitor, workSegment)); maybeAddCatalogItem(catalogCategory); } finally { @@ -157,7 +141,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } } - protected void handleSearchResult(MarketplaceCategory catalogCategory, SearchResult result, + protected void handleSearchResult(MarketplaceCategory catalogCategory, ISearchResult result, final IProgressMonitor monitor) { if (!result.getNodes().isEmpty()) { int totalWork = 10000000; @@ -165,22 +149,22 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { ConcurrentTaskManager executor = new ConcurrentTaskManager(result.getNodes().size(), Messages.MarketplaceDiscoveryStrategy_loadingResources); try { - for (final Node node : result.getNodes()) { + for (final INode node : result.getNodes()) { final MarketplaceNodeCatalogItem catalogItem = new MarketplaceNodeCatalogItem(); catalogItem.setMarketplaceUrl(catalogDescriptor.getUrl()); catalogItem.setId(node.getId()); catalogItem.setName(getCatalogItemName(node)); catalogItem.setCategoryId(catalogCategory.getId()); - Categories categories = node.getCategories(); + ICategories categories = node.getCategories(); if (categories != null) { - for (Category category : categories.getCategory()) { - catalogItem.addTag(new Tag(Category.class, category.getId(), category.getName())); + 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()); - Ius ius = node.getIus(); + IIus ius = node.getIus(); if (ius != null) { List<String> discoveryIus = new ArrayList<String>(ius.getIu()); for (int x = 0; x < discoveryIus.size(); ++x) { @@ -281,7 +265,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } } - private String getCatalogItemName(Node node) { + private String getCatalogItemName(INode node) { String name = node.getName(); String version = node.getVersion(); return version == null || version.length() == 0 ? name : NLS.bind( @@ -306,7 +290,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { items.add(catalogItem); } - private void createIcon(CatalogItem catalogItem, final Node node) { + private void createIcon(CatalogItem catalogItem, final INode node) { Icon icon = new Icon(); // don't know the size icon.setImage32(node.getImage()); @@ -315,13 +299,13 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { catalogItem.setIcon(icon); } - public void performQuery(Market market, Category category, String queryText, IProgressMonitor monitor) + public void performQuery(IMarket market, ICategory category, String queryText, IProgressMonitor monitor) throws CoreException { final int totalWork = 1000000; SubMonitor progress = SubMonitor.convert(monitor, Messages.MarketplaceDiscoveryStrategy_searchingMarketplace, totalWork); try { - SearchResult result; + ISearchResult result; MarketplaceCategory catalogCategory = findMarketplaceCategory(progress.newChild(1)); catalogCategory.setContents(Contents.QUERY); @@ -335,8 +319,22 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { 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(MarketplaceClientUi.computeStatus(ex, Messages.MarketplaceDiscoveryStrategy_invalidFilter)); + } catch (NoSuchElementException ex) { + throw new CoreException(MarketplaceClientUi.computeStatus(ex, Messages.MarketplaceDiscoveryStrategy_unknownFilter)); + } + progress.setWorkRemaining(totalWork); - result = marketplaceService.search(market, category, queryText, progress.newChild(totalWork / 2)); + result = marketplaceService.search(resolvedMarket, resolvedCategory, queryText, + progress.newChild(totalWork / 2)); } handleSearchResult(catalogCategory, result, progress.newChild(totalWork / 2)); @@ -349,20 +347,68 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } } - private SearchResult performNodeQuery(String nodeUrl, IProgressMonitor progress) throws CoreException { - final Node[] queryNode = new Node[1]; + private 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 <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, Node node) { + protected boolean handleNode(CatalogDescriptor descriptor, String url, INode node) { queryNode[0] = node; return true; } }; if (urlHandler.handleUri(nodeUrl) && queryNode[0] != null) { - Node node = marketplaceService.getNode(queryNode[0], progress); + INode node = marketplaceService.getNode(queryNode[0], progress); SearchResult result = new SearchResult(); result.setMatchCount(1); - result.setNodes(Collections.singletonList(node)); + result.setNodes(Collections.singletonList((Node) node)); return result; } return null; @@ -374,7 +420,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { try { MarketplaceCategory catalogCategory = findMarketplaceCategory(new SubProgressMonitor(monitor, 1)); catalogCategory.setContents(Contents.RECENT); - SearchResult result = marketplaceService.recent(new SubProgressMonitor(monitor, totalWork / 2)); + ISearchResult result = marketplaceService.recent(new SubProgressMonitor(monitor, totalWork / 2)); handleSearchResult(catalogCategory, result, new SubProgressMonitor(monitor, totalWork / 2)); maybeAddCatalogItem(catalogCategory); } finally { @@ -382,14 +428,14 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } } - public void featured(IProgressMonitor monitor, final Market market, final Category category) throws CoreException { + public void featured(IProgressMonitor monitor, final IMarket market, final ICategory category) throws CoreException { final int totalWork = 1000000; monitor.beginTask(Messages.MarketplaceDiscoveryStrategy_searchingMarketplace, totalWork); try { MarketplaceCategory catalogCategory = findMarketplaceCategory(new SubProgressMonitor(monitor, 1)); catalogCategory.setContents(Contents.FEATURED); - SearchResult result = marketplaceService.featured(new SubProgressMonitor(monitor, totalWork / 2), market, - category); + ISearchResult result = marketplaceService.featured(market, category, + new SubProgressMonitor(monitor, totalWork / 2)); handleSearchResult(catalogCategory, result, new SubProgressMonitor(monitor, totalWork / 2)); maybeAddCatalogItem(catalogCategory); } finally { @@ -398,13 +444,12 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } public void popular(IProgressMonitor monitor) throws CoreException { - // FIXME: do we want popular or favorites? final int totalWork = 1000000; monitor.beginTask(Messages.MarketplaceDiscoveryStrategy_searchingMarketplace, totalWork); try { MarketplaceCategory catalogCategory = findMarketplaceCategory(new SubProgressMonitor(monitor, 1)); catalogCategory.setContents(Contents.POPULAR); - SearchResult result = marketplaceService.popular(new SubProgressMonitor(monitor, totalWork / 2)); + ISearchResult result = marketplaceService.popular(new SubProgressMonitor(monitor, totalWork / 2)); handleSearchResult(catalogCategory, result, new SubProgressMonitor(monitor, totalWork / 2)); maybeAddCatalogItem(catalogCategory); } finally { @@ -422,13 +467,13 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { result.setNodes(new ArrayList<Node>()); Set<String> installedFeatures = computeInstalledFeatures(monitor); if (!monitor.isCanceled()) { - Set<Node> catalogNodes = marketplaceInfo.computeInstalledNodes(catalogDescriptor.getUrl(), + Set<INode> catalogNodes = marketplaceInfo.computeInstalledNodes(catalogDescriptor.getUrl(), installedFeatures); if (!catalogNodes.isEmpty()) { int unitWork = totalWork / (2 * catalogNodes.size()); - for (Node node : catalogNodes) { + for (INode node : catalogNodes) { node = marketplaceService.getNode(node, monitor); - result.getNodes().add(node); + result.getNodes().add((Node) node); monitor.worked(unitWork); } } else { @@ -442,7 +487,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } public void performQuery(IProgressMonitor monitor, Set<String> nodeIds) throws CoreException { - Set<Node> nodes = new HashSet<Node>(); + Set<INode> nodes = new HashSet<INode>(); for (String nodeId : nodeIds) { Node node = new Node(); node.setId(nodeId); @@ -451,7 +496,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { performNodeQuery(monitor, nodes); } - public void performNodeQuery(IProgressMonitor monitor, Set<Node> nodes) throws CoreException { + public void performNodeQuery(IProgressMonitor monitor, Set<? extends INode> nodes) throws CoreException { final int totalWork = 1000000; monitor.beginTask(Messages.MarketplaceDiscoveryStrategy_searchingMarketplace, totalWork); try { @@ -462,9 +507,9 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { if (!monitor.isCanceled()) { if (!nodes.isEmpty()) { int unitWork = totalWork / (2 * nodes.size()); - for (Node node : nodes) { + for (INode node : nodes) { node = marketplaceService.getNode(node, monitor); - result.getNodes().add(node); + result.getNodes().add((Node) node); monitor.worked(unitWork); } } else { @@ -502,7 +547,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { } if (catalogCategory == null) { - List<Market> markets = marketplaceService.listMarkets(new SubProgressMonitor(monitor, 10000)); + List<? extends IMarket> markets = marketplaceService.listMarkets(new SubProgressMonitor(monitor, 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 @@ -522,7 +567,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { return catalogCategory; } - public News performNewsDiscovery(IProgressMonitor monitor) throws CoreException { + public INews performNewsDiscovery(IProgressMonitor monitor) throws CoreException { return marketplaceService.news(monitor); } @@ -533,7 +578,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { Set<Node> nodes = new HashSet<Node>(); for (CatalogItem item : items) { Object data = item.getData(); - if (data instanceof Node) { + if (data instanceof INode) { nodes.add((Node) data); } } @@ -543,7 +588,7 @@ public class MarketplaceDiscoveryStrategy extends AbstractDiscoveryStrategy { String version = iu.getVersion() == null ? null : iu.getVersion().toString(); iuIdsAndVersions.add(id + "," + version); //$NON-NLS-1$ } - marketplaceService.reportInstallError(monitor, result, nodes, iuIdsAndVersions, resolutionDetails); + marketplaceService.reportInstallError(result, nodes, iuIdsAndVersions, resolutionDetails, monitor); } finally { monitor.done(); } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceInfo.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceInfo.java index ba30bf40..165581f4 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceInfo.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceInfo.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; @@ -33,6 +34,7 @@ import java.util.Set; import org.eclipse.core.runtime.Platform; import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; +import org.eclipse.epp.mpc.core.model.INode; /** * A means of knowing about how nodes map to IUs and visa versa. Can handle nodes from multiple marketplaces, and does a @@ -78,8 +80,8 @@ public class MarketplaceInfo { * all of the currently installed IUs * @return a set of node ids, or an empty set if there are no known installed nodes */ - public synchronized Set<Node> computeInstalledNodes(URL repositoryUrl, Set<String> installedIus) { - Set<Node> nodes = new HashSet<Node>(); + public synchronized Set<INode> computeInstalledNodes(URL repositoryUrl, Set<String> installedIus) { + Set<INode> nodes = new HashSet<INode>(); String keyPrefix = computeUrlKey(repositoryUrl) + '#'; for (Map.Entry<String, List<String>> entry : nodeKeyToIU.entrySet()) { @@ -110,7 +112,7 @@ public class MarketplaceInfo { * @deprecated use {@link #computeInstalled(Set, INode)} instead */ @Deprecated - public boolean computeInstalled(Set<String> installedFeatures, Set<URI> knownRepositories, Node node) { + public boolean computeInstalled(Set<String> installedFeatures, Set<URI> knownRepositories, INode node) { String updateurl = node.getUpdateurl(); if (updateurl == null) { // don't consider installed if there's no update site @@ -137,7 +139,7 @@ public class MarketplaceInfo { * Compute if the given node is installed. The given node must be fully realized, including its * {@link Node#getIus() ius}. */ - public boolean computeInstalled(Set<String> installedFeatures, Node node) { + public boolean computeInstalled(Set<String> installedFeatures, INode node) { if (node.getIus() != null && !node.getIus().getIu().isEmpty()) { List<String> ius = new ArrayList<String>(new HashSet<String>(node.getIus().getIu())); return computeInstalled(installedFeatures, ius); @@ -156,7 +158,7 @@ public class MarketplaceInfo { return installCount > 0; } - public synchronized void map(URL marketUrl, Node node) { + public synchronized void map(URL marketUrl, INode node) { String itemKey = computeItemKey(marketUrl, node); if (node.getIus() != null && !node.getIus().getIu().isEmpty()) { List<String> ius = new ArrayList<String>(new HashSet<String>(node.getIus().getIu())); @@ -189,7 +191,7 @@ public class MarketplaceInfo { } } - private String computeItemKey(URL marketUrl, Node item) { + private String computeItemKey(URL marketUrl, INode item) { return computeUrlKey(marketUrl) + '#' + item.getId(); } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java index c41d6046..a29051ad 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/MarketplaceNodeCatalogItem.java @@ -7,12 +7,16 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.catalog; import java.net.URL; +import java.util.EnumSet; +import java.util.Set; -import org.eclipse.epp.internal.mpc.core.service.Node; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; /** @@ -25,8 +29,8 @@ public class MarketplaceNodeCatalogItem extends CatalogItem { private Boolean updateAvailable; @Override - public Node getData() { - return (Node) super.getData(); + public INode getData() { + return (INode) super.getData(); } public URL getMarketplaceUrl() { @@ -45,6 +49,32 @@ public class MarketplaceNodeCatalogItem extends CatalogItem { this.updateAvailable = updateAvailable; } + public Set<Operation> getAvailableOperations() { + Set<Operation> available = EnumSet.noneOf(Operation.class); + MarketplaceNodeCatalogItem catalogItem = (MarketplaceNodeCatalogItem) getData(); + if (!catalogItem.getInstallableUnits().isEmpty()) { + if (isInstalled()) { + available.add(Operation.UNINSTALL); + if (maybeUpdateAvailable()) { + available.add(Operation.UPDATE); + } + } else if (maybeAvailable()) { + available.add(Operation.INSTALL); + } + } + return available; + } + + private boolean maybeAvailable() { + Boolean available = getAvailable(); + return available == null || Boolean.TRUE.equals(available); + } + + private boolean maybeUpdateAvailable() { + Boolean updateAvailable = getUpdateAvailable(); + return updateAvailable == null || Boolean.TRUE.equals(updateAvailable); + } + @Override public int hashCode() { final int prime = 31; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/Messages.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/Messages.java index 8ea97668..6952d3d6 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/Messages.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/Messages.java @@ -35,15 +35,25 @@ class Messages extends NLS { public static String MarketplaceDiscoveryStrategy_findingInstalled; + public static String MarketplaceDiscoveryStrategy_invalidFilter; + public static String MarketplaceDiscoveryStrategy_loadingMarketplace; public static String MarketplaceDiscoveryStrategy_loadingResources; public static String MarketplaceDiscoveryStrategy_Name_and_Version; + public static String MarketplaceDiscoveryStrategy_noNameMatch; + + public static String MarketplaceDiscoveryStrategy_noUrlMatch; + public static String MarketplaceDiscoveryStrategy_searchingMarketplace; public static String MarketplaceDiscoveryStrategy_sendingErrorNotification; + + public static String MarketplaceDiscoveryStrategy_unidentifiableItem; + + public static String MarketplaceDiscoveryStrategy_unknownFilter; static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/messages.properties b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/messages.properties index 918b47cd..c325678a 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/messages.properties +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/catalog/messages.properties @@ -18,8 +18,13 @@ MarketplaceCatalog_queryFailed=Query failed to complete MarketplaceCatalog_queryingMarketplace=Querying marketplace MarketplaceDiscoveryStrategy_catalogCategory=Catalog category MarketplaceDiscoveryStrategy_findingInstalled=Finding Installed +MarketplaceDiscoveryStrategy_invalidFilter=Invalid filter selection MarketplaceDiscoveryStrategy_loadingMarketplace=Loading marketplace MarketplaceDiscoveryStrategy_loadingResources=Loading resources MarketplaceDiscoveryStrategy_Name_and_Version={0} {1} +MarketplaceDiscoveryStrategy_noNameMatch=No known item found for name '{0}' +MarketplaceDiscoveryStrategy_noUrlMatch=No known item found for url '{0}' MarketplaceDiscoveryStrategy_searchingMarketplace=Searching Marketplace MarketplaceDiscoveryStrategy_sendingErrorNotification=Sending Marketplace error notification +MarketplaceDiscoveryStrategy_unidentifiableItem=Unidentifiable item {0}: At least one of id, url or name must be set. +MarketplaceDiscoveryStrategy_unknownFilter=Unknown filter selection diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java index b5a9931f..1c5664fb 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/commands/MarketplaceWizardCommand.java @@ -8,12 +8,11 @@ * Contributors: * The Eclipse Foundation - initial API and implementation * Yatta Solutions - category filtering (bug 314936), error handling (bug 374105), - * multiselect hints (bug 337774) + * multiselect hints (bug 337774), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.commands; import java.lang.reflect.InvocationTargetException; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -31,11 +30,6 @@ 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.epp.internal.mpc.core.ServiceLocator; -import org.eclipse.epp.internal.mpc.core.service.Catalog; -import org.eclipse.epp.internal.mpc.core.service.CatalogService; -import org.eclipse.epp.internal.mpc.core.service.Category; -import org.eclipse.epp.internal.mpc.core.service.Market; import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; @@ -45,16 +39,22 @@ import org.eclipse.epp.internal.mpc.ui.wizards.ComboTagFilter; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceCatalogConfiguration; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceFilter; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard; +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizardDialog; -import org.eclipse.epp.internal.mpc.ui.wizards.Operation; +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.service.ICatalogService; +import org.eclipse.epp.mpc.core.service.ServiceHelper; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore; import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory; import org.eclipse.equinox.internal.p2.discovery.model.Tag; import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil; import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogFilter; import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.wizard.WizardDialog; @@ -73,7 +73,9 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle private String wizardState; - private Map<String, Operation> operationByNodeId; + private Map<String, Operation> operations; + + private WizardState wizardDialogState; public Object execute(ExecutionEvent event) throws ExecutionException { final MarketplaceCatalog catalog = new MarketplaceCatalog(); @@ -136,8 +138,8 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle for (CatalogCategory category : catalog.getCategories()) { if (category instanceof MarketplaceCategory) { MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category; - for (Market market : marketplaceCategory.getMarkets()) { - Tag marketTag = new Tag(Market.class, market.getId(), market.getName()); + for (IMarket market : marketplaceCategory.getMarkets()) { + Tag marketTag = new Tag(IMarket.class, market.getId(), market.getName()); marketTag.setData(market); choices.add(marketTag); } @@ -148,7 +150,7 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle }; marketFilter.setSelectAllOnNoSelection(true); marketFilter.setNoSelectionLabel(Messages.MarketplaceWizardCommand_allMarkets); - marketFilter.setTagClassification(Category.class); + marketFilter.setTagClassification(ICategory.class); marketFilter.setChoices(new ArrayList<Tag>()); final ComboTagFilter marketCategoryTagFilter = new ComboTagFilter() { @@ -159,7 +161,7 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle }; marketCategoryTagFilter.setSelectAllOnNoSelection(true); marketCategoryTagFilter.setNoSelectionLabel(Messages.MarketplaceWizardCommand_allCategories); - marketCategoryTagFilter.setTagClassification(Category.class); + marketCategoryTagFilter.setTagClassification(ICategory.class); marketCategoryTagFilter.setChoices(new ArrayList<Tag>()); final IPropertyChangeListener marketListener = new IPropertyChangeListener() { @@ -175,8 +177,8 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle configuration.getFilters().add(marketFilter); configuration.getFilters().add(marketCategoryTagFilter); configuration.setInitialState(wizardState); - if (operationByNodeId != null && !operationByNodeId.isEmpty()) { - configuration.setInitialOperationByNodeId(operationByNodeId); + if (operations != null && !operations.isEmpty()) { + configuration.setInitialOperations(operations); } for (CatalogFilter filter : configuration.getFilters()) { @@ -184,7 +186,7 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle } MarketplaceWizard wizard = new MarketplaceWizard(catalog, configuration); - + wizard.setInitialState(wizardDialogState); wizard.setWindowTitle(Messages.MarketplaceWizardCommand_eclipseMarketplace); WizardDialog dialog = new MarketplaceWizardDialog(WorkbenchUtil.getShell(), wizard); @@ -197,19 +199,19 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle Set<Tag> newChoices = new HashSet<Tag>(); List<Tag> choices = new ArrayList<Tag>(); - Set<Market> selectedMarkets = new HashSet<Market>(); + Set<IMarket> selectedMarkets = new HashSet<IMarket>(); for (Tag marketTag : marketFilter.getSelected()) { - selectedMarkets.add((Market) marketTag.getData()); + selectedMarkets.add((IMarket) marketTag.getData()); } final MarketplaceCatalog catalog = (MarketplaceCatalog) marketCategoryTagFilter.getCatalog(); for (CatalogCategory category : catalog.getCategories()) { if (category instanceof MarketplaceCategory) { MarketplaceCategory marketplaceCategory = (MarketplaceCategory) category; - for (Market market : marketplaceCategory.getMarkets()) { + for (IMarket market : marketplaceCategory.getMarkets()) { if (selectedMarkets.isEmpty() || selectedMarkets.contains(market)) { - for (Category marketCategory : market.getCategory()) { - Tag categoryTag = new Tag(Category.class, marketCategory.getId(), marketCategory.getName()); + for (ICategory marketCategory : market.getCategory()) { + Tag categoryTag = new Tag(ICategory.class, marketCategory.getId(), marketCategory.getName()); categoryTag.setData(marketCategory); if (newChoices.add(categoryTag)) { choices.add(categoryTag); @@ -239,19 +241,39 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle this.wizardState = wizardState; } - public void setOperationByNodeId(Map<String, Operation> operationByNodeId) { - this.operationByNodeId = operationByNodeId; + public void setWizardDialogState(WizardState wizardState) { + this.wizardDialogState = wizardState; + } + + /** + * @deprecated use {@link #setOperations(Map)} instead + */ + @Deprecated + public void setOperationByNodeId(Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> operationByNodeId) { + this.operations = org.eclipse.epp.internal.mpc.ui.wizards.Operation.mapAllBack(operationByNodeId); + } + + public void setOperations(Map<String, Operation> operationByNodeId) { + this.operations = operationByNodeId; + } + + public void setConfiguration(IMarketplaceClientConfiguration configuration) { + setCatalogDescriptors(configuration.getCatalogDescriptors()); + setOperations(configuration.getInitialOperations()); + setWizardState((String) configuration.getInitialState()); + setSelectedCatalogDescriptor(configuration.getCatalogDescriptor()); } public IStatus installRemoteCatalogs() { try { - final AtomicReference<List<Catalog>> result = new AtomicReference<List<Catalog>>(); + final AtomicReference<List<? extends ICatalog>> result = new AtomicReference<List<? extends ICatalog>>(); PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { - CatalogService catalogService = ServiceLocator.getInstance().getCatalogService(); - final List<Catalog> catalogs = catalogService.listCatalogs(monitor); + ICatalogService catalogService = ServiceHelper.getMarketplaceServiceLocator() + .getCatalogService(); + final List<? extends ICatalog> catalogs = catalogService.listCatalogs(monitor); result.set(catalogs); } catch (CoreException e) { throw new InvocationTargetException(e); @@ -259,22 +281,10 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle } }); - List<Catalog> catalogs = result.get(); - for (Catalog catalog : catalogs) { - CatalogDescriptor descriptor = new CatalogDescriptor(); - descriptor.setLabel(catalog.getName()); - descriptor.setUrl(new URL(catalog.getUrl())); - descriptor.setIcon(ImageDescriptor.createFromURL(new URL(catalog.getImageUrl()))); - descriptor.setDescription(catalog.getDescription()); - descriptor.setInstallFromAllRepositories(!catalog.isSelfContained()); - if (catalog.getDependencyRepository() != null) { - descriptor.setDependenciesRepository(new URL(catalog.getDependencyRepository())); - } + List<? extends ICatalog> catalogs = result.get(); + for (ICatalog catalog : catalogs) { + CatalogDescriptor descriptor = new CatalogDescriptor(catalog); registerOrOverrideCatalog(descriptor); - CatalogRegistry.getInstance().addCatalogBranding(descriptor, catalog.getBranding()); - if (catalog.getNews() != null) { - CatalogRegistry.getInstance().addCatalogNews(descriptor, catalog.getNews()); - } } } catch (InterruptedException ie) { return Status.CANCEL_STATUS; @@ -296,5 +306,4 @@ public class MarketplaceWizardCommand extends AbstractHandler implements IHandle } catalogRegistry.register(descriptor); } - } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/Messages.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/Messages.java index e5242cc1..a13abcc4 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/Messages.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/Messages.java @@ -15,6 +15,8 @@ import org.eclipse.osgi.util.NLS; class Messages extends NLS { private static final String BUNDLE_NAME = "org.eclipse.epp.internal.mpc.ui.operations.messages"; //$NON-NLS-1$ + public static String ProfileChangeOperationComputer_unknownOperation; + public static String ProvisioningOperation_commaSeparator; public static String ProvisioningOperation_configuringProvisioningOperation; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/ProfileChangeOperationComputer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/ProfileChangeOperationComputer.java index 54fda396..20677c28 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/ProfileChangeOperationComputer.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/ProfileChangeOperationComputer.java @@ -4,10 +4,11 @@ * 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: * Tasktop Technologies - initial API and implementation * JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.operations; @@ -51,7 +52,7 @@ import org.eclipse.swt.widgets.Display; * A job that configures a p2 provisioning operation for installing/updating/removing one or more {@link CatalogItem * connectors}. The bulk of the installation work is done by p2; this class just sets up the p2 repository meta-data and * selects the appropriate features to install. - * + * * @author David Green * @author Steffen Pingel */ @@ -73,7 +74,26 @@ public class ProfileChangeOperationComputer extends AbstractProvisioningOperatio /** * uninstall features */ - UNINSTALL + UNINSTALL; + + public static OperationType map(org.eclipse.epp.mpc.ui.Operation operation) { + if (operation == null) { + return null; + } + switch (operation) { + case INSTALL: + return INSTALL; + case UNINSTALL: + return UNINSTALL; + case UPDATE: + return UPDATE; + case NONE: + return null; + default: + throw new IllegalArgumentException(NLS.bind(Messages.ProfileChangeOperationComputer_unknownOperation, + operation)); + } + } } private final OperationType operationType; @@ -308,7 +328,7 @@ public class ProfileChangeOperationComputer extends AbstractProvisioningOperatio /** * Remove ius from the given list where the current profile already contains a newer version of that iu. - * + * * @param installableUnits * @throws CoreException */ diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/messages.properties b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/messages.properties index 41491f9a..05dacdab 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/messages.properties +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/operations/messages.properties @@ -8,6 +8,7 @@ # Contributors: # The Eclipse Foundation - initial API and implementation ############################################################################### +ProfileChangeOperationComputer_unknownOperation=Unknown operation: {0} ProvisioningOperation_commaSeparator=, ProvisioningOperation_configuringProvisioningOperation=Configuring provisioning operation ProvisioningOperation_nothingToUpdate=There is nothing to update. diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java index 86213f18..e0354865 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/BrowseCatalogItem.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - bug 397004 + * Yatta Solutions - bug 397004, bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -17,12 +17,12 @@ import java.net.URL; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.epp.internal.mpc.core.service.Category; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Market; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; import org.eclipse.epp.mpc.ui.CatalogDescriptor; import org.eclipse.equinox.internal.p2.ui.discovery.wizards.AbstractDiscoveryItem; import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources; @@ -101,8 +101,8 @@ public class BrowseCatalogItem extends AbstractDiscoveryItem<CatalogDescriptor> ContentType contentType = viewer.getQueryContentType(); if (contentType == ContentType.SEARCH) { String queryText = viewer.getQueryText(); - Category queryCategory = viewer.getQueryCategory(); - Market queryMarket = viewer.getQueryMarket(); + ICategory queryCategory = viewer.getQueryCategory(); + IMarket queryMarket = viewer.getQueryMarket(); String path = new DefaultMarketplaceService(url).computeRelativeSearchUrl(queryMarket, queryCategory, queryText, false); if (path != null) { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java index 8fb8cb3d..982581fa 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/DiscoveryItem.java @@ -7,6 +7,7 @@ * * Contributors: * Tasktop Technologies - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -15,13 +16,14 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.MessageFormat; -import org.eclipse.epp.internal.mpc.core.service.Node; -import org.eclipse.epp.internal.mpc.core.service.Tag; -import org.eclipse.epp.internal.mpc.core.service.Tags; import org.eclipse.epp.internal.mpc.core.util.TextUtil; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; import org.eclipse.epp.internal.mpc.ui.util.Util; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.model.ITag; +import org.eclipse.epp.mpc.core.model.ITags; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.AbstractCatalogSource; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.eclipse.equinox.internal.p2.discovery.model.Overview; @@ -324,7 +326,7 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< hookLinkListener(installInfoLink, new LinkListener() { @Override protected void selected(String href) { - browser.openUrl(((Node) connector.getData()).getUrl()); + browser.openUrl(((INode) connector.getData()).getUrl()); } }); GridDataFactory.swtDefaults().align(SWT.TRAIL, SWT.CENTER).grab(false, true).applyTo(installInfoLink); @@ -348,8 +350,8 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< Integer installsTotal = null; Integer installsRecent = null; - if (connector.getData() instanceof Node) { - Node node = (Node) connector.getData(); + if (connector.getData() instanceof INode) { + INode node = (INode) connector.getData(); installsTotal = node.getInstallsTotal(); installsRecent = node.getInstallsRecent(); } @@ -374,16 +376,16 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< installInfo.append(installInfoText.substring(formatTotalsStart + totalText.length())); } } else { - if (shareSolutionLink != null) {
- shareSolutionLink.setShowText(true);
- }
+ if (shareSolutionLink != null) { + shareSolutionLink.setShowText(true); + } } } private void createSocialButtons(Composite parent) { Integer favorited = null; - if (connector.getData() instanceof Node) { - Node node = (Node) connector.getData(); + if (connector.getData() instanceof INode) { + INode node = (INode) connector.getData(); favorited = node.getFavorited(); } if (favorited == null || getCatalogItemUrl() == null) { @@ -407,7 +409,7 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< Label spacer = new Label(this, SWT.NONE); spacer.setText(" ");//$NON-NLS-1$ GridDataFactory.fillDefaults().indent(0, BUTTONBAR_MARGIN_TOP).align(SWT.CENTER, SWT.FILL).applyTo(spacer); - }
+ } } private void createRatingsButton(Composite parent, Integer favoritedCount) { @@ -477,8 +479,8 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< private String getCatalogItemUrl() { Object data = connector.getData(); - if (data instanceof Node) { - Node node = (Node) data; + if (data instanceof INode) { + INode node = (INode) data; return node.getUrl(); } return null; @@ -622,11 +624,11 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< .grab(true, false) .applyTo(tagsLink); - Tags tags = ((Node) connector.getData()).getTags(); + ITags tags = ((INode) connector.getData()).getTags(); if (tags == null) { return; } - for (Tag tag : tags.getTags()) { + for (ITag tag : tags.getTags()) { String tagName = tag.getName(); appendLink(tagsLink, tagName, SWT.NORMAL).data = tagName; tagsLink.append(" "); //$NON-NLS-1$ @@ -649,6 +651,14 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< && connector.getOverview().getSummary().length() > 0; } + /** + * @deprecated use {@link #maybeModifySelection(Operation)} + */ + @Deprecated + protected boolean maybeModifySelection(org.eclipse.epp.internal.mpc.ui.wizards.Operation operation) { + return maybeModifySelection(operation.getOperation()); + } + protected boolean maybeModifySelection(Operation operation) { viewer.modifySelection(connector, operation); return true; @@ -659,8 +669,16 @@ public class DiscoveryItem<T extends CatalogItem> extends AbstractDiscoveryItem< return getData().isSelected(); } - public Operation getOperation() { - return viewer.getSelectionModel().getOperation(getData()); + /** + * @deprecated use {@link #getSelectedOperation()} instead + */ + @Deprecated + public org.eclipse.epp.internal.mpc.ui.wizards.Operation getOperation() { + return org.eclipse.epp.internal.mpc.ui.wizards.Operation.map(getSelectedOperation()); + } + + public Operation getSelectedOperation() { + return viewer.getSelectionModel().getSelectedOperation(getData()); } public void propertyChange(PropertyChangeEvent evt) { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FeatureSelectionWizardPage.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FeatureSelectionWizardPage.java index ae51247c..48473028 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FeatureSelectionWizardPage.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/FeatureSelectionWizardPage.java @@ -8,6 +8,7 @@ * Contributors: * The Eclipse Foundation - initial API and implementation * JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -82,8 +83,8 @@ public class FeatureSelectionWizardPage extends WizardPage { public Image getImage(Object element) { if (element instanceof FeatureEntry) { FeatureEntry entry = (FeatureEntry) element; - switch (entry.getParent().getOperation()) { - case CHECK_FOR_UPDATES: + switch (entry.getParent().getSelectedOperation()) { + case UPDATE: if (entry.isInstalled()) { return MarketplaceClientUiPlugin.getInstance() .getImageRegistry() @@ -294,7 +295,7 @@ public class FeatureSelectionWizardPage extends WizardPage { private void updateFeatures() { viewer.setInput(getWizard().getSelectionModel()); ResolveFeatureNamesOperation operation = new ResolveFeatureNamesOperation(new ArrayList<CatalogItem>( - getWizard().getSelectionModel().getItemToOperation().keySet())) { + getWizard().getSelectionModel().getItemToSelectedOperation().keySet())) { Display display = getControl().getDisplay(); diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/IDiscoveryItemFactory.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/IDiscoveryItemFactory.java new file mode 100644 index 00000000..9756158b --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/IDiscoveryItemFactory.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.ui.wizards; + +import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; +import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources; +import org.eclipse.jface.window.IShellProvider; +import org.eclipse.swt.widgets.Composite; + +public interface IDiscoveryItemFactory { + public <T extends CatalogItem> DiscoveryItem<T> createDiscoveryItem(T connector, MarketplaceViewer viewer, + Composite parent, DiscoveryResources resources, IShellProvider shellProvider, IMarketplaceWebBrowser browser); +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ItemButtonController.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ItemButtonController.java index 00beb479..5faa2971 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ItemButtonController.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ItemButtonController.java @@ -7,10 +7,12 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; @@ -18,7 +20,7 @@ import org.eclipse.swt.widgets.Button; /** * A controller that controls the multi-state install/uninstall button - * + * * @author David Green */ @SuppressWarnings("rawtypes") @@ -31,7 +33,7 @@ class ItemButtonController { DISABLED(Messages.ItemButtonController_install, Operation.NONE, true), // UPDATE_DISABLED(Messages.ItemButtonController_update, Operation.NONE, true), // UPDATE(Messages.ItemButtonController_update, Operation.NONE, false), // - UPDATE_PENDING(Messages.ItemButtonController_updatePending, Operation.CHECK_FOR_UPDATES, false); + UPDATE_PENDING(Messages.ItemButtonController_updatePending, Operation.UPDATE, false); final String label; @@ -137,11 +139,11 @@ class ItemButtonController { buttonState = ButtonState.DISABLED; secondaryButtonState = ButtonState.DISABLED; } else { - Operation operation = item.getOperation(); + Operation operation = item.getSelectedOperation(); boolean installed = isItemInstalled(); if (installed) { switch (operation) { - case CHECK_FOR_UPDATES: + case UPDATE: buttonState = ButtonState.UPDATE_PENDING; secondaryButtonState = ButtonState.UNINSTALL; break; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceBrowserIntegration.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceBrowserIntegration.java index 3adcdde8..35229a66 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceBrowserIntegration.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceBrowserIntegration.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - error handling (bug 374105), news (bug 401721) + * Yatta Solutions - error handling (bug 374105), news (bug 401721), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -19,7 +19,7 @@ import org.eclipse.swt.browser.WindowEvent; /** * Browser integration for the marketplace that intercepts calls to install buttons and causes them to open the * marketplace wizard. - * + * * @author dgreen * @author Carsten Reckord */ @@ -41,7 +41,7 @@ OpenWindowListener { @Override protected boolean handleInstallRequest(SolutionInstallationInfo installInfo, String url) { - MarketplaceUrlHandler.triggerInstall(installInfo); + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.triggerInstall(installInfo); return true; } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java index d8c6f072..72022a28 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceCatalogConfiguration.java @@ -7,27 +7,33 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogConfiguration; +import org.eclipse.osgi.util.NLS; /** * @author David Green */ -public class MarketplaceCatalogConfiguration extends CatalogConfiguration { +public class MarketplaceCatalogConfiguration extends CatalogConfiguration implements IMarketplaceClientConfiguration { private List<CatalogDescriptor> catalogDescriptors = new ArrayList<CatalogDescriptor>(); private CatalogDescriptor catalogDescriptor; private String initialState; - private Map<String, Operation> initialOperationByNodeId; + private Map<String, Operation> initialOperations; public MarketplaceCatalogConfiguration() { setShowTagFilter(false); @@ -37,6 +43,14 @@ public class MarketplaceCatalogConfiguration extends CatalogConfiguration { setShowCategories(false); } + public MarketplaceCatalogConfiguration(IMarketplaceClientConfiguration configuration) { + this(); + setCatalogDescriptors(configuration.getCatalogDescriptors()); + setCatalogDescriptor(configuration.getCatalogDescriptor()); + setInitialState(configuration.getInitialState()); + setInitialOperations(configuration.getInitialOperations()); + } + public List<CatalogDescriptor> getCatalogDescriptors() { return catalogDescriptors; } @@ -53,6 +67,16 @@ public class MarketplaceCatalogConfiguration extends CatalogConfiguration { this.catalogDescriptor = catalogDescriptor; } + public void setInitialState(Object state) { + if (state == null || state instanceof String) { + String stateString = (String) state; + setInitialState(stateString); + } else { + throw new IllegalArgumentException(NLS.bind(Messages.MarketplaceCatalogConfiguration_invalidStateObject, + state)); + } + } + public void setInitialState(String initialState) { this.initialState = initialState; } @@ -61,12 +85,29 @@ public class MarketplaceCatalogConfiguration extends CatalogConfiguration { return initialState; } - public Map<String, Operation> getInitialOperationByNodeId() { - return initialOperationByNodeId; + public Map<String, Operation> getInitialOperations() { + return initialOperations == null ? null : Collections.unmodifiableMap(initialOperations); } - public void setInitialOperationByNodeId(Map<String, Operation> initialOperationByNodeId) { - this.initialOperationByNodeId = initialOperationByNodeId; + public void setInitialOperations(Map<String, Operation> initialOperations) { + this.initialOperations = new LinkedHashMap<String, Operation>(initialOperations); } + /** + * @deprecated use {@link #getInitialOperations()} instead + */ + @Deprecated + public Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> getInitialOperationByNodeId() { + Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> map = org.eclipse.epp.internal.mpc.ui.wizards.Operation.mapAll(initialOperations); + return map == null ? null : Collections.unmodifiableMap(map); + } + + /** + * @deprecated use {@link #setInitialOperations(Map)} instead + */ + @Deprecated + public void setInitialOperationByNodeId( + Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> initialOperationByNodeId) { + this.initialOperations = org.eclipse.epp.internal.mpc.ui.wizards.Operation.mapAllBack(initialOperationByNodeId); + } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java new file mode 100644 index 00000000..e9779fb8 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceClientService.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2010 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.ui.wizards; + +import java.util.Set; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType; +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration; +import org.eclipse.epp.mpc.ui.IMarketplaceClientService; + +public class MarketplaceClientService implements IMarketplaceClientService { + + public IMarketplaceClientConfiguration newConfiguration() { + return new MarketplaceCatalogConfiguration(); + } + + public void open(IMarketplaceClientConfiguration configuration) { + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + execute(command); + } + + public void openSelected(IMarketplaceClientConfiguration configuration) { + checkInitialState(configuration); + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setContentType(ContentType.SELECTION); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + execute(command); + } + + public void openInstalled(IMarketplaceClientConfiguration configuration) { + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setContentType(ContentType.INSTALLED); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + execute(command); + } + + public void openSearch(IMarketplaceClientConfiguration configuration, IMarket market, ICategory category, + String query) { + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setContentType(ContentType.SEARCH); + wizardState.setFilterMarket(market); + wizardState.setFilterCategory(category); + wizardState.setFilterQuery(query); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + execute(command); + } + + public void open(IMarketplaceClientConfiguration configuration, Set<INode> nodes) { + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setContent(nodes); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + execute(command); + } + + public void openProvisioning(IMarketplaceClientConfiguration configuration) { + checkInitialState(configuration); + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setConfiguration(configuration); + WizardState wizardState = new WizardState(); + wizardState.setProceedWithInstallation(true); + command.setWizardDialogState(wizardState); + execute(command); + } + + private void checkInitialState(IMarketplaceClientConfiguration configuration) { + if (configuration.getInitialState() == null + && (configuration.getInitialOperations() == null || configuration.getInitialOperations().isEmpty())) { + throw new IllegalArgumentException(Messages.MarketplaceClientService_noProvisioningOperation); + } + } + + private void execute(MarketplaceWizardCommand command) { + try { + command.execute(new ExecutionEvent()); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java index 0c777893..f09eff31 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceDropAdapter.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -14,7 +15,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceUrlHandler.SolutionInstallationInfo; +import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler; +import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java index 83c55a8d..7f8bf433 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplacePage.java @@ -7,8 +7,8 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - news (bug 401721) - * JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow + * Yatta Solutions - news (bug 401721), public API (bug 432803) + * JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -19,16 +19,18 @@ import java.util.Set; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.epp.internal.mpc.core.service.CatalogBranding; -import org.eclipse.epp.internal.mpc.core.service.Category; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.News; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.util.Util; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType; +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState; +import org.eclipse.epp.mpc.core.model.ICatalogBranding; +import org.eclipse.epp.mpc.core.model.ICategory; +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.ui.CatalogDescriptor; import org.eclipse.equinox.internal.p2.ui.discovery.DiscoveryImages; import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogPage; @@ -176,7 +178,7 @@ public class MarketplacePage extends CatalogPage { return; } SelectionModel selectionModel = getWizard().getSelectionModel(); - int newSelectionSize = selectionModel.getItemToOperation().size(); + int newSelectionSize = selectionModel.getItemToSelectedOperation().size(); // important: we don't do anything if the selection is empty, since CatalogViewer // sets the empty selection whenever the catalog is updated. @@ -214,7 +216,7 @@ public class MarketplacePage extends CatalogPage { return; } if (tab == newsTabItem) { - final News news = getNews(); + final INews news = getNews(); boolean wasUpdated = newsViewer.isUpdated(news); newsViewer.showNews(news); if (wasUpdated) { @@ -229,6 +231,14 @@ public class MarketplacePage extends CatalogPage { } return; } + ContentType currentContentType = getViewer().getContentType(); + if (currentContentType != null) { + TabItem tabItem = getTabItem(currentContentType); + if (tabItem == tab) { + setActiveTab(currentContentType); + return; + } + } for (ContentType contentType : ContentType.values()) { if (getTabItem(contentType) == tab) { setActiveTab(contentType); @@ -292,7 +302,7 @@ public class MarketplacePage extends CatalogPage { newsTabItem = new TabItem(tabFolder, SWT.NULL | SWT.BOLD); newsTabItem.setText(Messages.MarketplacePage_DefaultNewsTitle); - News news = getNews(); + INews news = getNews(); if (news == null) { newsTabItem.dispose(); return; @@ -318,7 +328,7 @@ public class MarketplacePage extends CatalogPage { } private void updateNewsStatus() { - News news = getNews(); + INews news = getNews(); Image tabImage = null; if (news != null && newsViewer.isUpdated(news)) { @@ -330,9 +340,9 @@ public class MarketplacePage extends CatalogPage { newsTabItem.getParent().layout(); } - private News getNews() { + private INews getNews() { CatalogDescriptor descriptor = configuration.getCatalogDescriptor(); - News news = CatalogRegistry.getInstance().getCatalogNews(descriptor); + INews news = CatalogRegistry.getInstance().getCatalogNews(descriptor); return news; } @@ -371,7 +381,7 @@ public class MarketplacePage extends CatalogPage { final String originalText = selectionLink.getText(); String text = " "; //$NON-NLS-1$ - int count = getWizard().getSelectionModel().getItemToOperation().size(); + int count = getWizard().getSelectionModel().getItemToSelectedOperation().size(); if (count == 1) { text = Messages.MarketplacePage_linkShowSelection_One; } else if (count > 0) { @@ -491,11 +501,16 @@ public class MarketplacePage extends CatalogPage { disableTabSelection = true; updateTitle(); CatalogDescriptor descriptor = configuration.getCatalogDescriptor(); - CatalogBranding branding = CatalogRegistry.getInstance().getCatalogBranding(descriptor); + ICatalogBranding branding = descriptor == null ? null : descriptor.getCatalogBranding(); if (branding == null) { branding = getDefaultBranding(); } + TabItem selectedTabItem = null; + int selectionIndex = tabFolder.getSelectionIndex(); + if (selectionIndex != -1) { + selectedTabItem = tabFolder.getItem(selectionIndex); + } newsTabItem.dispose(); searchTabItem.dispose(); recentTabItem.dispose(); @@ -504,26 +519,53 @@ public class MarketplacePage extends CatalogPage { boolean hasSearchTab = branding.hasSearchTab(); if (hasSearchTab) { + boolean isSelected = (selectedTabItem == searchTabItem); createSearchTab(); searchTabItem.setText(branding.getSearchTabName()); + if (isSelected) { + selectedTabItem = searchTabItem; + } } boolean hasRecentTab = branding.hasRecentTab(); if (hasRecentTab) { + boolean isSelected = (selectedTabItem == recentTabItem); createRecentTab(); recentTabItem.setText(branding.getRecentTabName()); + if (isSelected) { + selectedTabItem = recentTabItem; + } } boolean hasPopularTab = branding.hasPopularTab(); if (hasPopularTab) { + boolean isSelected = (selectedTabItem == popularTabItem); createPopularTab(); popularTabItem.setText(branding.getPopularTabName()); + if (isSelected) { + selectedTabItem = popularTabItem; + } } - createInstalledTab(); + { + boolean isSelected = (selectedTabItem == installedTabItem); + createInstalledTab(); + if (isSelected) { + selectedTabItem = installedTabItem; + } + } - createNewsTab(); + { + boolean isSelected = (selectedTabItem == newsTabItem); + createNewsTab(); + if (isSelected) { + selectedTabItem = newsTabItem; + } + } + if (selectedTabItem == null || selectedTabItem.isDisposed()) { + selectedTabItem = tabFolder.getItem(0); + } - tabFolder.setSelection(searchTabItem); + tabFolder.setSelection(selectedTabItem); try { ImageDescriptor wizardIconDescriptor; @@ -539,7 +581,7 @@ public class MarketplacePage extends CatalogPage { disableTabSelection = false; } - private CatalogBranding getDefaultBranding() { + private ICatalogBranding getDefaultBranding() { CatalogBranding branding = new CatalogBranding(); branding.setHasSearchTab(true); branding.setHasPopularTab(true); @@ -583,6 +625,16 @@ public class MarketplacePage extends CatalogPage { updateBranding(); } + public void showNews(CatalogDescriptor catalogDescriptor) { + IStatus proceed = Status.OK_STATUS; + if (catalogDescriptor != null) { + proceed = showMarketplace(catalogDescriptor); + } + if (proceed.isOK()) { + setActiveTab(newsTabItem); + } + } + public void show(CatalogDescriptor catalogDescriptor, MarketplaceViewer.ContentType content) { IStatus proceed = Status.OK_STATUS; if (catalogDescriptor != null) { @@ -593,7 +645,7 @@ public class MarketplacePage extends CatalogPage { } } - public void show(CatalogDescriptor catalogDescriptor, final Set<Node> nodes) { + public void show(CatalogDescriptor catalogDescriptor, final Set<? extends INode> nodes) { IStatus proceed = Status.OK_STATUS; if (catalogDescriptor != null) { proceed = showMarketplace(catalogDescriptor); @@ -604,7 +656,7 @@ public class MarketplacePage extends CatalogPage { } } - public void search(CatalogDescriptor catalogDescriptor, final Market searchMarket, final Category searchCategory, + public void search(CatalogDescriptor catalogDescriptor, final IMarket searchMarket, final ICategory searchCategory, final String searchString) { IStatus proceed = Status.OK_STATUS; if (catalogDescriptor != null) { @@ -616,6 +668,22 @@ public class MarketplacePage extends CatalogPage { } } + protected void initialize(WizardState initialState) { + ContentType contentType = initialState.getContentType(); + if (contentType != null && contentType != ContentType.SEARCH) { + show(configuration.getCatalogDescriptor(), contentType); + } else if (initialState.getContent() != null && !initialState.getContent().isEmpty()) { + show(configuration.getCatalogDescriptor(), initialState.getContent()); + } else { + IMarket market = initialState.getFilterMarket(); + ICategory category = initialState.getFilterCategory(); + String query = initialState.getFilterQuery(); + if (market != null || category != null || query != null) { + search(configuration.getCatalogDescriptor(), market, category, query); + } + } + } + @Override public void dispose() { if (marketplaceSwitcher != null) { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceUrlHandler.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceUrlHandler.java index 8dfd7d40..b7f62dac 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceUrlHandler.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceUrlHandler.java @@ -7,382 +7,59 @@ * * Contributors: * Tasktop Technologies - initial API and implementation - * Yatta Solutions - news (bug 401721) + * Yatta Solutions - news (bug 401721), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Node; -import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; -import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; -import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; import org.eclipse.epp.mpc.ui.CatalogDescriptor; -import org.eclipse.ui.statushandlers.StatusManager; /** * @author David Green * @author Benjamin Muskalla * @author Carsten Reckord + * @deprecated use {@link org.eclipse.epp.mpc.ui.MarketplaceUrlHandler} instead */ -public abstract class MarketplaceUrlHandler { - - public static final String DESCRIPTOR_HINT = "org.eclipse.epp.mpc.descriptorHint"; //$NON-NLS-1$ - - public static final String MPC_INSTALL_URI = "/mpc/install?"; //$NON-NLS-1$ - - public static final String SITE_SEARCH_URI = "/search/site"; //$NON-NLS-1$ - - private static final Pattern CONTENT_URL_PATTERN = Pattern.compile("(?:^|/)content/([^/#?]+)"); //$NON-NLS-1$ - - private static final Pattern NODE_URL_PATTERN = Pattern.compile("(?:^|/)node/([^/#?]+)"); //$NON-NLS-1$ +@Deprecated +public abstract class MarketplaceUrlHandler extends org.eclipse.epp.mpc.ui.MarketplaceUrlHandler { - public static class SolutionInstallationInfo { - private String installId; + /** + * @deprecated use {@link org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo} instead + */ + @Deprecated + public static class SolutionInstallationInfo extends + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo { - private String state; - - private CatalogDescriptor catalogDescriptor; - - public String getInstallId() { - return installId; + public SolutionInstallationInfo() { + super(); } - public String getState() { - return state; - } - - public CatalogDescriptor getCatalogDescriptor() { - return catalogDescriptor; + protected SolutionInstallationInfo(String installId, String state, CatalogDescriptor catalogDescriptor) { + super(installId, state, catalogDescriptor); } } - protected static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ - - private static final String PARAM_SPLIT_REGEX = "&"; //$NON-NLS-1$ - - private static final String EQUALS_REGEX = "="; //$NON-NLS-1$ - - private static final String MPC_STATE = "mpc_state"; //$NON-NLS-1$ - - private static final String MPC_INSTALL = "mpc_install"; //$NON-NLS-1$ - public static SolutionInstallationInfo createSolutionInstallInfo(String url) { - String query; - try { - query = new URL(url).getQuery(); - } catch (MalformedURLException e) { - return null; - } - if (query == null) { - return null; - } - String[] params = query.split(PARAM_SPLIT_REGEX); - String installId = null; - String state = null; - for (String param : params) { - String[] keyValue = param.split(EQUALS_REGEX); - if(keyValue.length == 2) { - String key = keyValue[0]; - String value = keyValue[1]; - if (key.equals(MPC_INSTALL)) { - installId = value; - } else if (key.equals(MPC_STATE)) { - state = value; - } - } - } - if (installId != null) { - CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(url); - SolutionInstallationInfo info = new SolutionInstallationInfo(); - info.installId = installId; - info.state = state; - if (descriptor != null) { - info.catalogDescriptor = descriptor; - } else { - try { - info.catalogDescriptor = new CatalogDescriptor(new URL(url), DESCRIPTOR_HINT); - } catch (MalformedURLException e) { - return null; - } - } - return info; - } - return null; - } - - public static boolean isPotentialSolution(String url) { - return url != null && url.contains(MPC_INSTALL); - } - - public static void triggerInstall(SolutionInstallationInfo info) { - String installId = info.getInstallId(); - String mpcState = info.getState(); - CatalogDescriptor catalogDescriptor = info.getCatalogDescriptor(); - MarketplaceWizardCommand command = new MarketplaceWizardCommand(); - command.setSelectedCatalogDescriptor(catalogDescriptor); - try { - if (mpcState != null) { - command.setWizardState(URLDecoder.decode(mpcState, UTF_8)); - } - Map<String, Operation> nodeIdToOperation = new HashMap<String, Operation>(); - nodeIdToOperation.put(URLDecoder.decode(installId, UTF_8), Operation.INSTALL); - command.setOperationByNodeId(nodeIdToOperation); - } catch (UnsupportedEncodingException e1) { - throw new IllegalStateException(e1); - } - try { - command.execute(new ExecutionEvent()); - } catch (ExecutionException e) { - IStatus status = MarketplaceClientUi.computeStatus(e, - Messages.MarketplaceBrowserIntegration_cannotOpenMarketplaceWizard); - StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); - } - } - - public boolean handleUri(String uri) { - if (isPotentialSolution(uri)) { - SolutionInstallationInfo installInfo = createSolutionInstallInfo(uri); - if (installInfo != null) { - return handleInstallRequest(installInfo, uri); - } - } - - CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(uri); - if (descriptor == null) { - descriptor = handleUnknownCatalog(uri); - if (descriptor == null) { - return false; - } - } - - String baseUri; - try { - baseUri = descriptor.getUrl().toURI().toString(); - if (!baseUri.endsWith("/")) { //$NON-NLS-1$ - baseUri += '/'; - } - } catch (URISyntaxException e) { - // should be unreachable - throw new IllegalStateException(e); - } - - if (!uri.startsWith(baseUri)) { - uri = resolve(uri, baseUri, descriptor); - if (!uri.startsWith(baseUri)) { - return false; - } - } - String relativeUri = uri.substring(baseUri.length()); - if (relativeUri.startsWith(DefaultMarketplaceService.API_FAVORITES_URI)) { - return handleFavorites(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_FEATURED_URI)) { - return handleFeatured(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_NODE_CONTENT_URI)) { - return handleNodeContent(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_NODE_URI)) { - return handleNode(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_POPULAR_URI)) { - return handlePopular(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_RECENT_URI)) { - return handleRecent(descriptor, relativeUri); - } else if (relativeUri.startsWith(DefaultMarketplaceService.API_SEARCH_URI) - || relativeUri.startsWith(DefaultMarketplaceService.API_SEARCH_URI_FULL)) { - return handleSolrSearch(descriptor, relativeUri); - } else if (relativeUri.startsWith(SITE_SEARCH_URI.substring(1))) { - return handleSiteSearch(descriptor, relativeUri); - } else { - return handleUnknownPath(descriptor, relativeUri); - } - } - - protected String resolve(String url, String baseUri, CatalogDescriptor descriptor) { - if (url.startsWith("https:") && baseUri.startsWith("http:")) { //$NON-NLS-1$ //$NON-NLS-2$ - url = "http:" + url.substring("https:".length()); //$NON-NLS-1$ //$NON-NLS-2$ - } else if (url.startsWith("http:") && baseUri.startsWith("https:")) { //$NON-NLS-1$ //$NON-NLS-2$ - url = "https:" + url.substring("http:".length()); //$NON-NLS-1$ //$NON-NLS-2$ - } - return url; - } - - protected boolean handleUnknownPath(CatalogDescriptor descriptor, String url) { - return false; - } - - private boolean handleSolrSearch(CatalogDescriptor descriptor, String url) { - try { - Map<String, String> params = new HashMap<String, String>(); - String searchString = parseSearchQuery(descriptor, url, params); - return handleSearch(descriptor, url, searchString, params); - } catch (MalformedURLException e) { - // don't handle malformed URLs - return false; - } catch (URISyntaxException e) { - // don't handle malformed URLs - return false; - } - } - - private boolean handleSiteSearch(CatalogDescriptor descriptor, String url) { - try { - Map<String, String> params = new HashMap<String, String>(); - String searchString = parseSearchQuery(descriptor, url, params); + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo solutionInstallInfo = org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.createSolutionInstallInfo(url); - // convert queries of this format - // f[0]=im_taxonomy_vocabulary_1:38&f[1]=im_taxonomy_vocabulary_3:31 - // to internal solr format - // filter=tid:38 tid:31 - StringBuilder filter = new StringBuilder(); - for (Iterator<String> i = params.values().iterator(); i.hasNext();) { - String str = i.next(); - if (str.startsWith("im_taxonomy_vocabulary_")) { //$NON-NLS-1$ - int sep = str.indexOf(':'); - if (sep != -1) { - String tid = str.substring(sep + 1); - if (filter.length() > 0) { - filter.append(' '); - } - filter.append(tid); - i.remove(); - } - } - } - return handleSearch(descriptor, url, searchString, params); - } catch (MalformedURLException e) { - // don't handle malformed URLs - return false; - } catch (URISyntaxException e) { - // don't handle malformed URLs - return false; - } + return wrap(solutionInstallInfo); } - private String parseSearchQuery(CatalogDescriptor descriptor, String url, Map<String, String> params) - throws URISyntaxException, MalformedURLException { - URI searchUri = new URL(descriptor.getUrl(), url).toURI(); - String path = searchUri.getPath(); - if (path.endsWith("/")) { //$NON-NLS-1$ - path = path.substring(0, path.length() - 1); - } - int sep = path.lastIndexOf('/'); - String searchString = path.substring(sep + 1); - String query = searchUri.getQuery(); - if (query != null) { - extractParams(query, params); - } - return searchString; - } - - protected boolean handleSearch(CatalogDescriptor descriptor, String url, String searchString, - Map<String, String> params) { - return false; + private static SolutionInstallationInfo wrap( + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo solutionInstallInfo) { + return new SolutionInstallationInfo(solutionInstallInfo.getInstallId(), solutionInstallInfo.getState(), + solutionInstallInfo.getCatalogDescriptor()); } - private void extractParams(String query, Map<String, String> params) { - final String[] paramStrings = query.split("&"); //$NON-NLS-1$ - for (String param : paramStrings) { - final String[] parts = param.split("="); //$NON-NLS-1$ - if (parts.length == 2) { - params.put(parts[0], parts[1]); - } - } - } - - protected boolean handleRecent(CatalogDescriptor descriptor, String url) { - return false; - } - - protected boolean handlePopular(CatalogDescriptor descriptor, String url) { - return false; - } - - private boolean handleNode(CatalogDescriptor descriptor, String url) { - Matcher matcher = NODE_URL_PATTERN.matcher(url); - String id = null; - if (matcher.find()) { - id = matcher.group(1); - } - Node node = new Node(); - node.setId(id); - return handleNode(descriptor, url, node); - } - - private boolean handleNodeContent(CatalogDescriptor descriptor, String url) { - Matcher matcher = CONTENT_URL_PATTERN.matcher(url); - String title = null; - if (matcher.find()) { - title = matcher.group(1); - } - Node node = new Node(); - node.setUrl(url); - if (title != null) { - String base = descriptor.getUrl().toExternalForm(); - if (!base.endsWith("/")) { //$NON-NLS-1$ - base += "/"; //$NON-NLS-1$ - } - int titleEnd = matcher.end(); - if (titleEnd > -1) { - //clean the url of other query parameters - node.setUrl(base + url.substring(0, titleEnd)); - } else { - //unknown format, leave as-is - node.setUrl(base + url); - } - } - return handleNode(descriptor, url, node); - } - - protected boolean handleNode(CatalogDescriptor descriptor, String url, Node node) { - return false; - } - - private boolean handleFeatured(CatalogDescriptor descriptor, String url) { - Matcher matcher = Pattern.compile("(?:^|/)featured/(\\d+)(?:,(\\d+))?").matcher(url); //$NON-NLS-1$ - String cat = null; - String market = null; - if (matcher.find()) { - cat = matcher.group(1); - if (matcher.groupCount() > 1) { - market = matcher.group(2); - } - } - return handleFeatured(descriptor, url, cat, market); - } - - protected boolean handleFeatured(CatalogDescriptor descriptor, String url, String category, String market) { - return false; - } - - protected boolean handleFavorites(CatalogDescriptor descriptor, String url) { + protected boolean handleInstallRequest(SolutionInstallationInfo installInfo, String url) { return false; } - protected CatalogDescriptor handleUnknownCatalog(String url) { - if (url.startsWith("https:")) { //$NON-NLS-1$ - url = "http:" + url.substring("https:".length()); //$NON-NLS-1$ //$NON-NLS-2$ - return CatalogRegistry.getInstance().findCatalogDescriptor(url); - } else if (url.startsWith("http:")) { //$NON-NLS-1$ - url = "https:" + url.substring("http:".length()); //$NON-NLS-1$ //$NON-NLS-2$ - return CatalogRegistry.getInstance().findCatalogDescriptor(url); + @Override + protected boolean handleInstallRequest( + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo installInfo, String url) { + if (installInfo instanceof SolutionInstallationInfo) { + return handleInstallRequest((SolutionInstallationInfo) installInfo, url); } - return null; - } - - protected boolean handleInstallRequest(SolutionInstallationInfo installInfo, String url) { - return false; + return handleInstallRequest(wrap(installInfo), url); } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java index ba0fc28b..c407a20f 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceViewer.java @@ -8,7 +8,7 @@ * Contributors: * The Eclipse Foundation - initial API and implementation * Yatta Solutions - error handling (bug 374105), header layout (bug 341014), - * news (bug 401721) + * news (bug 401721), public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -26,15 +26,18 @@ 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.epp.internal.mpc.core.service.Category; import org.eclipse.epp.internal.mpc.core.service.Identifiable; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; +import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory.Contents; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IIdentifiable; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.Catalog; import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; @@ -58,6 +61,8 @@ import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Button; @@ -65,6 +70,8 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.statushandlers.StatusManager; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; /** * @author Steffen Pingel @@ -117,9 +124,9 @@ public class MarketplaceViewer extends CatalogViewer { private String queryText; - private Market queryMarket; + private IMarket queryMarket; - private Category queryCategory; + private ICategory queryCategory; private ContentType queryContentType; @@ -131,6 +138,8 @@ public class MarketplaceViewer extends CatalogViewer { private final List<IPropertyChangeListener> listeners = new LinkedList<IPropertyChangeListener>(); + private IDiscoveryItemFactory discoveryItemFactory; + public MarketplaceViewer(Catalog catalog, IShellProvider shellProvider, MarketplaceWizard wizard) { super(catalog, shellProvider, wizard.getContainer(), wizard.getConfiguration()); this.browser = wizard; @@ -184,6 +193,7 @@ public class MarketplaceViewer extends CatalogViewer { ((MarketplaceFilter) filter).catalogUpdated(wasCancelled); } } + setFilters(queryMarket, queryCategory, queryText); } @Override @@ -197,7 +207,6 @@ public class MarketplaceViewer extends CatalogViewer { doQuery(); } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected ControlListItem<?> doCreateViewerItem(Composite parent, Object element) { if (element instanceof CatalogItem) { @@ -207,8 +216,7 @@ public class MarketplaceViewer extends CatalogViewer { return new BrowseCatalogItem(parent, getResources(), shellProvider, browser, (MarketplaceCategory) catalogItem.getCategory(), catalogDescriptor, this); } else { - DiscoveryItem discoveryItem = new DiscoveryItem(parent, SWT.NONE, getResources(), shellProvider, - browser, catalogItem, this); + DiscoveryItem<CatalogItem> discoveryItem = createDiscoveryItem(parent, catalogItem); discoveryItem.setSelected(getCheckedItems().contains(catalogItem)); return discoveryItem; } @@ -227,7 +235,16 @@ public class MarketplaceViewer extends CatalogViewer { return super.doCreateViewerItem(parent, element); } - public void show(Set<Node> nodes) { + private DiscoveryItem<CatalogItem> createDiscoveryItem(Composite parent, CatalogItem catalogItem) { + if (discoveryItemFactory != null) { + return discoveryItemFactory.createDiscoveryItem(catalogItem, this, parent, getResources(), shellProvider, + browser); + } + return new DiscoveryItem<CatalogItem>(parent, SWT.NONE, getResources(), shellProvider, browser, catalogItem, + this); + } + + public void show(Set<? extends INode> nodes) { ContentType newContentType = ContentType.SEARCH; ContentType oldContentType = contentType; contentType = newContentType; @@ -236,7 +253,7 @@ public class MarketplaceViewer extends CatalogViewer { doQuery(null, null, null, nodes); } - public void search(Market market, Category category, String query) { + public void search(IMarket market, ICategory category, String query) { ContentType newContentType = ContentType.SEARCH; ContentType oldContentType = contentType; contentType = newContentType; @@ -250,19 +267,19 @@ public class MarketplaceViewer extends CatalogViewer { doQuery(market, category, query, null); } - private void setFilters(Market market, Category category, String query) { - setFindText(query); + private void setFilters(IMarket market, ICategory category, String query) { + setFindText(query == null ? "" : query); //$NON-NLS-1$ for (CatalogFilter filter : getConfiguration().getFilters()) { if (filter instanceof AbstractTagFilter) { AbstractTagFilter tagFilter = (AbstractTagFilter) filter; - if (tagFilter.getTagClassification() == Category.class) { + if (tagFilter.getTagClassification() == ICategory.class) { List<Tag> choices = tagFilter.getChoices(); Tag tag = choices.isEmpty() ? null : choices.get(0); if (tag != null) { - Identifiable data = null; - if (tag.getTagClassifier() == Market.class) { + IIdentifiable data = null; + if (tag.getTagClassifier() == IMarket.class) { data = market; - } else if (tag.getTagClassifier() == Category.class) { + } else if (tag.getTagClassifier() == ICategory.class) { data = category; } else { continue; @@ -271,13 +288,13 @@ public class MarketplaceViewer extends CatalogViewer { if (data != null) { for (Tag choice : choices) { final Object choiceData = choice.getData(); - if (data == choiceData || data.equalsId(choiceData)) { + if (choiceData == data || matches(data, choiceData)) { tag = choice; break; } } } - tagFilter.setSelected(tag == null ? null : Collections.singleton(tag)); + tagFilter.setSelected(tag == null ? Collections.<Tag> emptySet() : Collections.singleton(tag)); //we expect a query to happen next, so don't fire a property change resulting in an additional query tagFilter.updateUi(); } @@ -286,7 +303,16 @@ public class MarketplaceViewer extends CatalogViewer { } } + private static boolean matches(IIdentifiable data, final Object tagData) { + return tagData instanceof IIdentifiable && Identifiable.matches((IIdentifiable) tagData, data); + } + private void doQuery() { + initQueryFromFilters(); + doQuery(queryMarket, queryCategory, queryText, null); + } + + private void initQueryFromFilters() { queryMarket = null; queryCategory = null; queryText = null; @@ -295,20 +321,19 @@ public class MarketplaceViewer extends CatalogViewer { for (CatalogFilter filter : getConfiguration().getFilters()) { if (filter instanceof AbstractTagFilter) { AbstractTagFilter tagFilter = (AbstractTagFilter) filter; - if (tagFilter.getTagClassification() == Category.class) { + if (tagFilter.getTagClassification() == ICategory.class) { Tag tag = tagFilter.getSelected().isEmpty() ? null : tagFilter.getSelected().iterator().next(); if (tag != null) { - if (tag.getTagClassifier() == Market.class) { - queryMarket = (Market) tag.getData(); - } else if (tag.getTagClassifier() == Category.class) { - queryCategory = (Category) tag.getData(); + if (tag.getTagClassifier() == IMarket.class) { + queryMarket = (IMarket) tag.getData(); + } else if (tag.getTagClassifier() == ICategory.class) { + queryCategory = (ICategory) tag.getData(); } } } } } queryText = findText; - doQuery(queryMarket, queryCategory, queryText, null); } public void doQueryForTag(String tag) { @@ -339,7 +364,8 @@ public class MarketplaceViewer extends CatalogViewer { firePropertyChangeEvent(new PropertyChangeEvent(source, property, oldValue, newValue)); } - private void doQuery(final Market market, final Category category, final String queryText, final Set<Node> nodes) { + private void doQuery(final IMarket market, final ICategory category, final String queryText, + final Set<? extends INode> nodes) { try { final ContentType queryType = contentType; queryContentType = queryType; @@ -358,8 +384,8 @@ public class MarketplaceViewer extends CatalogViewer { break; case SELECTION: Set<String> nodeIds = new HashSet<String>(); - for (CatalogItem item : getSelectionModel().getItemToOperation().keySet()) { - nodeIds.add(((Node) item.getData()).getId()); + for (CatalogItem item : getSelectionModel().getItemToSelectedOperation().keySet()) { + nodeIds.add(((INode) item.getData()).getId()); } result[0] = getCatalog().performQuery(monitor, nodeIds); break; @@ -489,8 +515,27 @@ public class MarketplaceViewer extends CatalogViewer { @Override protected StructuredViewer doCreateViewer(Composite container) { + ServiceReference<IDiscoveryItemFactory> serviceReference = null; + final BundleContext bundleContext = MarketplaceClientUiPlugin.getInstance().getBundle().getBundleContext(); + try { + serviceReference = bundleContext.getServiceReference(IDiscoveryItemFactory.class); + if (serviceReference != null) { + discoveryItemFactory = bundleContext.getService(serviceReference); + } + } catch (Exception ex) { + //fall back + MarketplaceClientUi.error(ex); + } StructuredViewer viewer = super.doCreateViewer(container); viewer.setSorter(null); + if (serviceReference != null) { + final ServiceReference<IDiscoveryItemFactory> ref = serviceReference; + viewer.getControl().addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + bundleContext.ungetService(ref); + } + }); + } return viewer; } @@ -502,6 +547,14 @@ public class MarketplaceViewer extends CatalogViewer { throw new UnsupportedOperationException(); } + /** + * @deprecated use {@link #modifySelection(CatalogItem, Operation)} instead + */ + @Deprecated + protected void modifySelection(CatalogItem connector, org.eclipse.epp.internal.mpc.ui.wizards.Operation operation) { + modifySelection(connector, operation == null ? null : operation.getOperation()); + } + protected void modifySelection(CatalogItem connector, Operation operation) { if (operation == null) { throw new IllegalArgumentException(); @@ -548,7 +601,7 @@ public class MarketplaceViewer extends CatalogViewer { @Override public List<CatalogItem> getCheckedItems() { List<CatalogItem> items = new ArrayList<CatalogItem>(); - for (Entry<CatalogItem, Operation> entry : getSelectionModel().getItemToOperation().entrySet()) { + for (Entry<CatalogItem, Operation> entry : getSelectionModel().getItemToSelectedOperation().entrySet()) { if (entry.getValue() != Operation.NONE) { items.add(entry.getKey()); } @@ -568,31 +621,31 @@ public class MarketplaceViewer extends CatalogViewer { /** * the text for the current query */ - String getQueryText() { + public String getQueryText() { return queryText; } /** * the category for the current query - * + * * @return the market or null if no category has been selected */ - Category getQueryCategory() { + public ICategory getQueryCategory() { return queryCategory; } /** * the market for the current query - * + * * @return the market or null if no market has been selected */ - Market getQueryMarket() { + public IMarket getQueryMarket() { return queryMarket; } /** * the content type for the current query - * + * * @return the content type or null if it's unknown */ ContentType getQueryContentType() { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java index 17539b95..7e0d5921 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/MarketplaceWizard.java @@ -7,7 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation - * Yatta Solutions - news (bug 401721) + * Yatta Solutions - news (bug 401721), public API (bug 432803) * JBoss (Pascal Rapicault) - Bug 406907 - Add p2 remediation page to MPC install flow *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -19,6 +19,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collection; @@ -30,6 +31,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -43,13 +46,21 @@ import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; +import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; import org.eclipse.epp.internal.mpc.ui.operations.AbstractProvisioningOperation; import org.eclipse.epp.internal.mpc.ui.operations.FeatureDescriptor; import org.eclipse.epp.internal.mpc.ui.operations.ProfileChangeOperationComputer; import org.eclipse.epp.internal.mpc.ui.operations.ProfileChangeOperationComputer.OperationType; +import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType; import org.eclipse.epp.internal.mpc.ui.wizards.SelectionModel.CatalogItemEntry; import org.eclipse.epp.internal.mpc.ui.wizards.SelectionModel.FeatureEntry; +import org.eclipse.epp.mpc.core.model.ICategory; +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.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.MarketplaceUrlHandler; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.AbstractDiscoveryStrategy; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.eclipse.equinox.internal.p2.ui.ProvUI; @@ -76,7 +87,7 @@ import org.eclipse.ui.statushandlers.StatusManager; /** * A wizard for interacting with a marketplace service. - * + * * @author David Green * @author Carsten Reckord */ @@ -90,6 +101,68 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile private static final String DEBUG_NEWS_URL = MarketplaceClientUi.BUNDLE_ID + "/news/url"; //$NON-NLS-1$ + public static class WizardState { + private ContentType contentType; + + private Set<INode> content; + + private IMarket filterMarket; + + private ICategory filterCategory; + + private String filterQuery; + + private Boolean proceedWithInstallation; + + public ContentType getContentType() { + return contentType; + } + + public void setContentType(ContentType contentType) { + this.contentType = contentType; + } + + public Set<INode> getContent() { + return content; + } + + public void setContent(Set<INode> content) { + this.content = content; + } + + public IMarket getFilterMarket() { + return filterMarket; + } + + public void setFilterMarket(IMarket filterMarket) { + this.filterMarket = filterMarket; + } + + public ICategory getFilterCategory() { + return filterCategory; + } + + public void setFilterCategory(ICategory filterCategory) { + this.filterCategory = filterCategory; + } + + public String getFilterQuery() { + return filterQuery; + } + + public void setFilterQuery(String filterQuery) { + this.filterQuery = filterQuery; + } + + public Boolean getProceedWithInstallation() { + return proceedWithInstallation; + } + + public void setProceedWithInstallation(Boolean proceedWithInstallation) { + this.proceedWithInstallation = proceedWithInstallation; + } + } + private Set<String> installedFeatures; private SelectionModel selectionModel; @@ -114,6 +187,8 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile private String errorMessage; + private WizardState initialState; + public String getErrorMessage() { return errorMessage; } @@ -168,30 +243,48 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile } initialSelectionInitialized = true; initializeCatalog(); - try { - getContainer().run(true, true, new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - new SelectionModelStateSerializer(getCatalog(), getSelectionModel()).deserialize(monitor, - getConfiguration().getInitialState(), getConfiguration().getInitialOperationByNodeId()); + if (getConfiguration().getInitialState() != null || getConfiguration().getInitialOperations() != null) { + try { + getContainer().run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + new SelectionModelStateSerializer(getCatalog(), getSelectionModel()).deserialize( + getConfiguration().getInitialState(), getConfiguration().getInitialOperations(), + monitor); + } + }); + } catch (InvocationTargetException e) { + throw new CoreException(MarketplaceClientUi.computeStatus(e, + Messages.MarketplaceViewer_unexpectedException)); + } catch (InterruptedException e) { + // user canceled + throw new CoreException(Status.CANCEL_STATUS); + } + for (Entry<CatalogItem, Operation> entry : getSelectionModel().getItemToSelectedOperation().entrySet()) { + if (entry.getValue() != Operation.NONE) { + entry.getKey().setSelected(true); } - }); - } catch (InvocationTargetException e) { - throw new CoreException( - MarketplaceClientUi.computeStatus(e, Messages.MarketplaceViewer_unexpectedException)); - } catch (InterruptedException e) { - // user canceled - throw new CoreException(Status.CANCEL_STATUS); - } - for (Entry<CatalogItem, Operation> entry : getSelectionModel().getItemToOperation().entrySet()) { - if (entry.getValue() != Operation.NONE) { - entry.getKey().setSelected(true); } } + WizardState initialState = getInitialState(); + if (initialState != null && getStartingPage() == getCatalogPage()) { + getCatalogPage().initialize(initialState); + } } boolean wantInitializeInitialSelection() { - return !initialSelectionInitialized - && (getConfiguration().getInitialState() != null || getConfiguration().getInitialOperationByNodeId() != null); + if (initialSelectionInitialized) { + return false; + } else if (getConfiguration().getInitialState() != null || getConfiguration().getInitialOperations() != null) { + return true; + } else if (initialState != null) { + WizardState initialState = getInitialState(); + if ((initialState.getContent() != null && !initialState.getContent().isEmpty()) + || (initialState.getContentType() != null && initialState.getContentType() != ContentType.SEARCH) + || (initialState.getFilterCategory() != null || initialState.getFilterMarket() != null || initialState.getFilterQuery() != null)) { + return true; + } + } + return false; } @Override @@ -307,7 +400,10 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile public IWizardPage getStartingPage() { if (getConfiguration().getCatalogDescriptor() != null) { if (wantInitializeInitialSelection()) { - return getFeatureSelectionWizardPage(); + WizardState initialState = getInitialState(); + if (initialState == null || !Boolean.FALSE.equals(initialState.getProceedWithInstallation())) { + return getFeatureSelectionWizardPage(); + } } return getCatalogPage(); } @@ -416,31 +512,18 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile } public void openUrl(String url) { - CatalogDescriptor catalogDescriptor = getConfiguration().getCatalogDescriptor(); - URL catalogUrl = catalogDescriptor.getUrl(); - URI catalogUri; - try { - catalogUri = catalogUrl.toURI(); - } catch (URISyntaxException e) { - // should never happen - throw new IllegalStateException(e); - } + String catalogUrl = getCatalogUrl(); if (WorkbenchBrowserSupport.getInstance().isInternalWebBrowserAvailable() - && url.toLowerCase().startsWith(catalogUri.toString().toLowerCase())) { + && url.toLowerCase().startsWith(catalogUrl.toLowerCase())) { int style = IWorkbenchBrowserSupport.AS_EDITOR | IWorkbenchBrowserSupport.LOCATION_BAR | IWorkbenchBrowserSupport.NAVIGATION_BAR; - String browserId = "MPC-" + catalogUri.toString().replaceAll("[^a-zA-Z0-9_-]", "_"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String browserId = "MPC-" + catalogUrl.replaceAll("[^a-zA-Z0-9_-]", "_"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ try { + CatalogDescriptor catalogDescriptor = getConfiguration().getCatalogDescriptor(); IWebBrowser browser = WorkbenchBrowserSupport.getInstance().createBrowser(style, browserId, catalogDescriptor.getLabel(), catalogDescriptor.getDescription()); final String originalUrl = url; - if (url.indexOf('?') == -1) { - url += '?'; - } else { - url += '&'; - } - String state = new SelectionModelStateSerializer(getCatalog(), getSelectionModel()).serialize(); - url += "mpc=true&mpc_state=" + URLEncoder.encode(state, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + url = appendWizardState(url); browser.openURL(new URL(url)); // ORDER DEPENDENCY getContainer().getShell().close(); if (!hookLocationListener(browser)) { // ORDER DEPENDENCY @@ -453,14 +536,40 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile IStatus status = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, NLS.bind( Messages.MarketplaceWizard_cannotOpenUrl, new Object[] { url, e.getMessage() }), e); StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(e); // should never happen } } else { WorkbenchUtil.openUrl(url, IWorkbenchBrowserSupport.AS_EXTERNAL); } } + private String getCatalogUrl() { + CatalogDescriptor catalogDescriptor = getConfiguration().getCatalogDescriptor(); + URL catalogUrl = catalogDescriptor.getUrl(); + URI catalogUri; + try { + catalogUri = catalogUrl.toURI(); + } catch (URISyntaxException e) { + // should never happen + throw new IllegalStateException(e); + } + return catalogUri.toString(); + } + + private String appendWizardState(String url) { + try { + if (url.indexOf('?') == -1) { + url += '?'; + } else { + url += '&'; + } + String state = new SelectionModelStateSerializer(getCatalog(), getSelectionModel()).serialize(); + url += "mpc=true&mpc_state=" + URLEncoder.encode(state, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + return url; + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); // should never happen + } + } + private boolean hookLocationListener(IWebBrowser webBrowser) { try { Field partField = findField(webBrowser.getClass(), "part", IWorkbenchPart.class); //$NON-NLS-1$ @@ -522,14 +631,14 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile if (getSelectionModel().computeProvisioningOperationViable()) { ProfileChangeOperationComputer provisioningOperation = null; try { - final Map<CatalogItem, Operation> itemToOperation = getSelectionModel().getItemToOperation(); + final Map<CatalogItem, Operation> itemToOperation = getSelectionModel().getItemToSelectedOperation(); final Set<CatalogItem> selectedItems = getSelectionModel().getSelectedCatalogItems(); OperationType operationType = null; for (Map.Entry<CatalogItem, Operation> entry : itemToOperation.entrySet()) { if (!selectedItems.contains(entry.getKey())) { continue; } - OperationType entryOperationType = entry.getValue().getOperationType(); + OperationType entryOperationType = OperationType.map(entry.getValue()); if (entryOperationType != null) { if (operationType == null || operationType == OperationType.UPDATE) { operationType = entryOperationType; @@ -631,7 +740,7 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile Set<CatalogItem> items = new HashSet<CatalogItem>(); Map<CatalogItem, Collection<String>> iusByCatalogItem = new HashMap<CatalogItem, Collection<String>>(); for (CatalogItemEntry entry : getSelectionModel().getCatalogItemEntries()) { - if (entry.getOperation() != Operation.INSTALL) { + if (entry.getSelectedOperation() != Operation.INSTALL) { continue; } List<FeatureEntry> features = entry.getChildren(); @@ -664,26 +773,27 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile protected void updateNews() { CatalogDescriptor catalogDescriptor = getConfiguration().getCatalogDescriptor(); - News news = null; + INews news = null; if (Boolean.parseBoolean(Platform.getDebugOption(DEBUG_NEWS_FLAG))) { // use debug override values String debugNewsUrl = Platform.getDebugOption(DEBUG_NEWS_URL); if (debugNewsUrl != null && debugNewsUrl.length() > 0) { - news = new News(); - news.setUrl(debugNewsUrl); + News debugNews = new News(); + news = debugNews; + debugNews.setUrl(debugNewsUrl); String debugNewsTitle = Platform.getDebugOption(DEBUG_NEWS_TITLE); if (debugNewsTitle == null || debugNewsTitle.length() == 0) { - news.setShortTitle("Debug News"); //$NON-NLS-1$ + debugNews.setShortTitle("Debug News"); //$NON-NLS-1$ } else { - news.setShortTitle(debugNewsTitle); + debugNews.setShortTitle(debugNewsTitle); } - news.setTimestamp(System.currentTimeMillis()); + debugNews.setTimestamp(System.currentTimeMillis()); } } if (news == null) { // try requesting news from marketplace try { - final News[] result = new News[1]; + final INews[] result = new INews[1]; getContainer().run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { @@ -712,4 +822,63 @@ public class MarketplaceWizard extends DiscoveryWizard implements InstallProfile CatalogRegistry.getInstance().addCatalogNews(catalogDescriptor, news); } + public Object suspendWizard() { + String catalogUrl = getCatalogUrl(); + String key = appendWizardState(catalogUrl); + getContainer().getShell().close(); + return key; + } + + public void setInitialState(WizardState initialState) { + this.initialState = initialState; + } + + public WizardState getInitialState() { + return initialState; + } + + public static void resumeWizard(Display display, Object state, boolean proceedWithInstall) { + String catalogUrl = (String) state; + if (proceedWithInstall) { + org.eclipse.epp.mpc.ui.MarketplaceUrlHandler.SolutionInstallationInfo installInfo = MarketplaceUrlHandler.createSolutionInstallInfo(catalogUrl); + if (installInfo != null) { + MarketplaceUrlHandler.triggerInstall(installInfo); + return; + } + } + CatalogDescriptor descriptor = catalogUrl == null ? null : CatalogRegistry.getInstance().findCatalogDescriptor( + catalogUrl); + final MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + if (descriptor != null) { + descriptor = new CatalogDescriptor(descriptor); + descriptor.setLabel(MarketplaceUrlHandler.DESCRIPTOR_HINT); + command.setSelectedCatalogDescriptor(descriptor); + } + String mpcState = MarketplaceUrlHandler.getMPCState(catalogUrl); + if (mpcState != null && mpcState.length() > 0) { + try { + command.setWizardState(URLDecoder.decode(mpcState, "UTF-8")); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); // should never happen + } + if (!proceedWithInstall) { + WizardState wizardState = new WizardState(); + wizardState.setProceedWithInstallation(false); + command.setWizardDialogState(wizardState); + } + } + display.asyncExec(new Runnable() { + + public void run() { + try { + command.execute(new ExecutionEvent()); + } catch (ExecutionException e) { + IStatus status = MarketplaceClientUi.computeStatus(e, + Messages.MarketplaceBrowserIntegration_cannotOpenMarketplaceWizard); + StatusManager.getManager().handle(status, + StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); + } + } + }); + } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java index ac3e69db..8d5ad0dd 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Messages.java @@ -97,6 +97,10 @@ class Messages extends NLS { public static String MarketplaceBrowserIntegration_cannotOpenMarketplaceWizard; + public static String MarketplaceCatalogConfiguration_invalidStateObject; + + public static String MarketplaceClientService_noProvisioningOperation; + public static String MarketplaceDropAdapter_0; public static String MarketplacePage_DefaultNewsTitle; @@ -161,6 +165,8 @@ class Messages extends NLS { public static String Operation_uninstall; + public static String Operation_unknownOperation; + public static String Operation_update; public static String OverviewToolTip_cannotRenderImage_reason; diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java index f39b5af6..ddbd9337 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsUrlHandler.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Yatta Solutions - initial API and implementation + * Yatta Solutions - initial API and implementation, public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -24,13 +24,14 @@ import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.epp.internal.mpc.core.service.Category; -import org.eclipse.epp.internal.mpc.core.service.Market; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCategory; import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceViewer.ContentType; +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.epp.mpc.ui.CatalogDescriptor; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogCategory; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.StructuredSelection; @@ -146,8 +147,8 @@ public class NewsUrlHandler extends MarketplaceUrlHandler implements LocationLis String filterParam = params.get("filter"); //$NON-NLS-1$ String[] filters = filterParam.split(" "); //$NON-NLS-1$ - Category searchCategory = null; - Market searchMarket = null; + ICategory searchCategory = null; + IMarket searchMarket = null; for (String filter : filters) { if (filter.startsWith("tid:")) { //$NON-NLS-1$ String id = filter.substring("tid:".length()); //$NON-NLS-1$ @@ -155,13 +156,13 @@ public class NewsUrlHandler extends MarketplaceUrlHandler implements LocationLis for (CatalogCategory catalogCategory : catalogCategories) { if (catalogCategory instanceof MarketplaceCategory) { MarketplaceCategory marketplaceCategory = (MarketplaceCategory) catalogCategory; - List<Market> markets = marketplaceCategory.getMarkets(); - for (Market market : markets) { + List<? extends IMarket> markets = marketplaceCategory.getMarkets(); + for (IMarket market : markets) { if (id.equals(market.getId())) { searchMarket = market; } else { - final List<Category> categories = market.getCategory(); - for (Category category : categories) { + final List<? extends ICategory> categories = market.getCategory(); + for (ICategory category : categories) { if (id.equals(category.getId())) { searchCategory = category; } @@ -190,7 +191,7 @@ public class NewsUrlHandler extends MarketplaceUrlHandler implements LocationLis } @Override - protected boolean handleNode(CatalogDescriptor descriptor, String url, Node node) { + protected boolean handleNode(CatalogDescriptor descriptor, String url, INode node) { viewer.getWizard().getCatalogPage().show(descriptor, Collections.singleton(node)); return true; } @@ -217,9 +218,9 @@ public class NewsUrlHandler extends MarketplaceUrlHandler implements LocationLis final SelectionModel selectionModel = viewer.getWizard().getSelectionModel(); SelectionModelStateSerializer stateSerializer = new SelectionModelStateSerializer( wizard.getCatalog(), selectionModel); - stateSerializer.deserialize(monitor, installId, nodeIdToOperation); + stateSerializer.deserialize(installId, nodeIdToOperation, monitor); - if (selectionModel.getItemToOperation().size() > 0) { + if (selectionModel.getItemToSelectedOperation().size() > 0) { Display display = wizard.getShell().getDisplay(); if (!display.isDisposed()) { display.asyncExec(new Runnable() { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsViewer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsViewer.java index 276a8cf6..154de12d 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsViewer.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/NewsViewer.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Yatta Solutions - initial API and implementation + * Yatta Solutions - initial API and implementation, public API (bug 432803) *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -19,6 +19,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.epp.internal.mpc.core.service.News; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; +import org.eclipse.epp.mpc.core.model.INews; import org.eclipse.epp.mpc.ui.CatalogDescriptor; import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil; import org.eclipse.jface.dialogs.IDialogConstants; @@ -157,7 +158,7 @@ public class NewsViewer { } } - public void showNews(News news) { + public void showNews(INews news) { final String url = news.getUrl(); if (url != null && url.length() > 0) { showUrl(url); @@ -200,7 +201,7 @@ public class NewsViewer { } } - public boolean isUpdated(News news) { + public boolean isUpdated(INews news) { String url = news.getUrl(); if (url == null || url.length() == 0) { return false; @@ -214,7 +215,7 @@ public class NewsViewer { return true; } - private String computeNewsStamp(News news) { + private String computeNewsStamp(INews news) { return NLS.bind("[{0}]{1}", news.getTimestamp(), news.getUrl()); //$NON-NLS-1$ } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Operation.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Operation.java index b3388814..da756596 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Operation.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/Operation.java @@ -7,29 +7,37 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + import org.eclipse.epp.internal.mpc.ui.operations.ProfileChangeOperationComputer.OperationType; +import org.eclipse.osgi.util.NLS; /** * Represents kinds of provisioning operations supported by the wizard - * + * * @author David Green + * @deprecated will be replaced completely by {@link org.eclipse.epp.mpc.ui.Operation} in the future. */ +@Deprecated public enum Operation { - INSTALL(OperationType.INSTALL, Messages.Operation_install), // - UNINSTALL(OperationType.UNINSTALL, Messages.Operation_uninstall), // - CHECK_FOR_UPDATES(OperationType.UPDATE, Messages.Operation_update), // - NONE(null, null); + INSTALL(OperationType.INSTALL, org.eclipse.epp.mpc.ui.Operation.INSTALL), // + UNINSTALL(OperationType.UNINSTALL, org.eclipse.epp.mpc.ui.Operation.UNINSTALL), // + CHECK_FOR_UPDATES(OperationType.UPDATE, org.eclipse.epp.mpc.ui.Operation.UPDATE), // + NONE(null, org.eclipse.epp.mpc.ui.Operation.NONE); private final OperationType operationType; - private final String label; + private final org.eclipse.epp.mpc.ui.Operation operation; - private Operation(OperationType operationType, String label) { + private Operation(OperationType operationType, org.eclipse.epp.mpc.ui.Operation operation) { this.operationType = operationType; - this.label = label; + this.operation = operation; } public OperationType getOperationType() { @@ -37,6 +45,70 @@ public enum Operation { } public String getLabel() { - return label; + return operation.getLabel(); + } + + public org.eclipse.epp.mpc.ui.Operation getOperation() { + return operation; + } + + public static Operation map(org.eclipse.epp.mpc.ui.Operation operation) { + if (operation == null) { + return null; + } + switch (operation) { + case INSTALL: + return INSTALL; + case UNINSTALL: + return UNINSTALL; + case UPDATE: + return CHECK_FOR_UPDATES; + case NONE: + return NONE; + default: + throw new IllegalArgumentException(NLS.bind(Messages.Operation_unknownOperation, operation)); + } + } + + public static org.eclipse.epp.mpc.ui.Operation mapBack(Operation operation) { + if (operation == null) { + return null; + } + switch (operation) { + case INSTALL: + return org.eclipse.epp.mpc.ui.Operation.INSTALL; + case UNINSTALL: + return org.eclipse.epp.mpc.ui.Operation.UNINSTALL; + case CHECK_FOR_UPDATES: + return org.eclipse.epp.mpc.ui.Operation.UPDATE; + case NONE: + return org.eclipse.epp.mpc.ui.Operation.NONE; + default: + throw new IllegalArgumentException(NLS.bind(Messages.Operation_unknownOperation, operation)); + } + } + + public static <T> Map<T, Operation> mapAll(Map<T, org.eclipse.epp.mpc.ui.Operation> operations) { + if (operations == null) { + return null; + } + Map<T, Operation> mappedOperations = new LinkedHashMap<T, Operation>(); + Set<Map.Entry<T, org.eclipse.epp.mpc.ui.Operation>> entrySet = operations.entrySet(); + for (Map.Entry<T, org.eclipse.epp.mpc.ui.Operation> entry : entrySet) { + mappedOperations.put(entry.getKey(), map(entry.getValue())); + } + return mappedOperations; + } + + public static <T> Map<T, org.eclipse.epp.mpc.ui.Operation> mapAllBack(Map<T, Operation> operations) { + if (operations == null) { + return null; + } + Map<T, org.eclipse.epp.mpc.ui.Operation> mappedOperations = new LinkedHashMap<T, org.eclipse.epp.mpc.ui.Operation>(); + Set<Map.Entry<T, Operation>> entrySet = operations.entrySet(); + for (Map.Entry<T, Operation> entry : entrySet) { + mappedOperations.put(entry.getKey(), entry.getValue() == null ? null : entry.getValue().getOperation()); + } + return mappedOperations; } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ProvisioningJobListener.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ProvisioningJobListener.java index 70c22883..473b3b7c 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ProvisioningJobListener.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ProvisioningJobListener.java @@ -7,11 +7,11 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; -import java.io.InputStream; -import java.net.URI; +import java.net.URL; import java.util.Set; import org.eclipse.core.runtime.CoreException; @@ -22,17 +22,16 @@ 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.epp.internal.mpc.core.service.DefaultMarketplaceService; -import org.eclipse.epp.internal.mpc.core.service.Node; -import org.eclipse.epp.internal.mpc.core.service.RemoteMarketplaceService; -import org.eclipse.epp.internal.mpc.core.util.TransportFactory; -import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceDiscoveryStrategy; +import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem; import org.eclipse.epp.internal.mpc.ui.util.ConcurrentTaskManager; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.service.IMarketplaceService; +import org.eclipse.epp.mpc.core.service.ServiceHelper; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; /** * A job listener that produces notifications of a successful install. - * + * * @author David Green */ class ProvisioningJobListener extends JobChangeAdapter { @@ -53,41 +52,27 @@ class ProvisioningJobListener extends JobChangeAdapter { } @Override - protected IStatus run(IProgressMonitor monitor) { + protected IStatus run(final IProgressMonitor monitor) { ConcurrentTaskManager taskManager = new ConcurrentTaskManager(installItems.size(), Messages.ProvisioningJobListener_notificationTaskName); - for (final CatalogItem item : installItems) { - taskManager.submit(new Runnable() { - public void run() { - Node node = (Node) item.getData(); - String url = node.getUrl(); - if (!url.endsWith("/")) { //$NON-NLS-1$ - url += "/"; //$NON-NLS-1$ - } - url += "success"; //$NON-NLS-1$ - - //FIXME workaround to access request metadata - //move success reporting to MarketplaceService API once we are not in API freeze to make this hack unnecessary - see bug 417068 - RemoteMarketplaceService<?> marketplaceService = new DefaultMarketplaceService(); - marketplaceService.setRequestMetaParameters(MarketplaceDiscoveryStrategy.computeDefaultRequestMetaParameters()); - url = marketplaceService.addMetaParameters(url); - try { - InputStream stream = TransportFactory.instance() - .getTransport() - .stream(new URI(url), new NullProgressMonitor()); + for (CatalogItem item : installItems) { + if (item instanceof MarketplaceNodeCatalogItem) { + final MarketplaceNodeCatalogItem nodeItem = (MarketplaceNodeCatalogItem) item; - try { - while (stream.read() != -1) { - // nothing to do + taskManager.submit(new Runnable() { + public void run() { + INode node = nodeItem.getData(); + URL marketplaceUrl = nodeItem.getMarketplaceUrl(); + IMarketplaceService marketplaceService = ServiceHelper.getMarketplaceServiceLocator().getMarketplaceService(marketplaceUrl.toString()); + marketplaceService.reportInstallSuccess(node, new NullProgressMonitor() { + @Override + public boolean isCanceled() { + return monitor.isCanceled(); } - } finally { - stream.close(); - } - } catch (Throwable e) { - //per bug 314028 logging this error is not useful. + }); } - } - }); + }); + } } try { taskManager.waitUntilFinished(monitor); diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java index 200e7157..55fbffb0 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModel.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -24,13 +25,14 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.operations.FeatureDescriptor; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.eclipse.osgi.util.NLS; /** * A model of selected items in the catalog. Provides feature-level selection fidelity, and stores the selected * operation. - * + * * @author David Green */ public class SelectionModel { @@ -47,7 +49,21 @@ public class SelectionModel { /** * Select the given item with the given operation. - * + * + * @param item + * the item to select + * @param operation + * the operation to perform. Providing {@link Operation#NONE} removes the selection + * @deprecated use {@link #select(CatalogItem, Operation)} instead + */ + @Deprecated + public void select(CatalogItem item, org.eclipse.epp.internal.mpc.ui.wizards.Operation operation) { + select(item, operation == null ? null : operation.getOperation()); + } + + /** + * Select the given item with the given operation. + * * @param item * the item to select * @param operation @@ -106,6 +122,15 @@ public class SelectionModel { return entries; } + /** + * @deprecated use {@link #createItemEntry(CatalogItem, Operation)} instead + */ + @Deprecated + public CatalogItemEntry createItemEntry(CatalogItem item, + org.eclipse.epp.internal.mpc.ui.wizards.Operation operation) { + return createItemEntry(item, operation == null ? null : operation.getOperation()); + } + public CatalogItemEntry createItemEntry(CatalogItem item, Operation operation) { CatalogItemEntry itemEntry = new CatalogItemEntry(item, operation); computeChildren(itemEntry); @@ -131,7 +156,7 @@ public class SelectionModel { private void computeInitialChecked(FeatureEntry entry) { Operation operation = entry.parent.operation; - if (operation == Operation.CHECK_FOR_UPDATES) { + if (operation == Operation.UPDATE) { if (entry.isInstalled()) { entry.checked = true; } @@ -156,7 +181,15 @@ public class SelectionModel { return item; } - public Operation getOperation() { + /** + * @deprecated use {@link #getSelectedOperation()} + */ + @Deprecated + public org.eclipse.epp.internal.mpc.ui.wizards.Operation getOperation() { + return org.eclipse.epp.internal.mpc.ui.wizards.Operation.map(operation); + } + + public Operation getSelectedOperation() { return operation; } @@ -285,7 +318,20 @@ public class SelectionModel { } - public Map<CatalogItem, Operation> getItemToOperation() { + /** + * @deprecated use {@link #getItemToSelectedOperation()} instead + */ + @Deprecated + public Map<CatalogItem, org.eclipse.epp.internal.mpc.ui.wizards.Operation> getItemToOperation() { + Map<CatalogItem, org.eclipse.epp.internal.mpc.ui.wizards.Operation> itemToOperation = new HashMap<CatalogItem, org.eclipse.epp.internal.mpc.ui.wizards.Operation>(); + Set<Entry<CatalogItem, Operation>> entrySet = this.itemToOperation.entrySet(); + for (Entry<CatalogItem, Operation> entry : entrySet) { + itemToOperation.put(entry.getKey(), org.eclipse.epp.internal.mpc.ui.wizards.Operation.map(entry.getValue())); + } + return itemToOperation; + } + + public Map<CatalogItem, Operation> getItemToSelectedOperation() { return Collections.unmodifiableMap(itemToOperation); } @@ -321,7 +367,16 @@ public class SelectionModel { return Collections.unmodifiableSet(items); } - public Operation getOperation(CatalogItem item) { + /** + * @deprecated use {@link #getSelectedOperation(CatalogItem)} instead + */ + @Deprecated + public org.eclipse.epp.internal.mpc.ui.wizards.Operation getOperation(CatalogItem item) { + Operation operation = getSelectedOperation(item); + return org.eclipse.epp.internal.mpc.ui.wizards.Operation.map(operation); + } + + public Operation getSelectedOperation(CatalogItem item) { Operation operation = itemToOperation.get(item); return operation == null ? Operation.NONE : operation; } @@ -345,7 +400,7 @@ public class SelectionModel { /** * Determine what message related to finishing the wizard should correspond to the current selection. - * + * * @return the message, or null if there should be no message. */ public IStatus computeProvisioningOperationViability() { @@ -364,7 +419,7 @@ public class SelectionModel { Messages.SelectionModel_countSolutions, entry.getValue().size()), entry.getKey() .getLabel())); } else if (operationToItem.size() == 2 && operationToItem.containsKey(Operation.INSTALL) - && operationToItem.containsKey(Operation.CHECK_FOR_UPDATES)) { + && operationToItem.containsKey(Operation.UPDATE)) { int count = 0; for (List<CatalogItem> items : operationToItem.values()) { count += items.size(); @@ -372,7 +427,7 @@ public class SelectionModel { return new Status(IStatus.INFO, MarketplaceClientUi.BUNDLE_ID, NLS.bind( Messages.SelectionModel_countSolutionsSelectedForInstallUpdate, count)); } else if (operationToItem.size() > 1) { - if (!(operationToItem.size() == 2 && operationToItem.containsKey(Operation.INSTALL) && operationToItem.containsKey(Operation.CHECK_FOR_UPDATES))) { + if (!(operationToItem.size() == 2 && operationToItem.containsKey(Operation.INSTALL) && operationToItem.containsKey(Operation.UPDATE))) { return new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, Messages.SelectionModel_cannotInstallRemoveConcurrently); } @@ -381,7 +436,7 @@ public class SelectionModel { } private Map<Operation, List<CatalogItem>> computeOperationToItem() { - Map<CatalogItem, Operation> itemToOperation = getItemToOperation(); + Map<CatalogItem, Operation> itemToOperation = getItemToSelectedOperation(); Map<Operation, List<CatalogItem>> catalogItemByOperation = new HashMap<Operation, List<CatalogItem>>(); for (Map.Entry<CatalogItem, Operation> entry : itemToOperation.entrySet()) { if (entry.getValue() == Operation.NONE) { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModelStateSerializer.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModelStateSerializer.java index 81d0058e..0c887e8c 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModelStateSerializer.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/SelectionModelStateSerializer.java @@ -7,23 +7,26 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog; import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceNodeCatalogItem; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.ui.Operation; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; /** * A mechanism for serializing/deserializing state - * + * * @author David Green */ public class SelectionModelStateSerializer { @@ -39,12 +42,12 @@ public class SelectionModelStateSerializer { public String serialize() { StringBuilder state = new StringBuilder(1024); - for (Map.Entry<CatalogItem, Operation> entry : selectionModel.getItemToOperation().entrySet()) { + for (Map.Entry<CatalogItem, Operation> entry : selectionModel.getItemToSelectedOperation().entrySet()) { if (entry.getValue() != Operation.NONE) { if (state.length() > 0) { state.append(' '); } - Node data = (Node) entry.getKey().getData(); + INode data = (INode) entry.getKey().getData(); state.append(data.getId()); state.append('='); state.append(entry.getValue().name()); @@ -59,8 +62,27 @@ public class SelectionModelStateSerializer { * the state to restore * @param operationByNodeIdExtras * additional operations to include + * @deprecated use {@link #deserialize(String, Map, IProgressMonitor)} instead */ - public void deserialize(IProgressMonitor monitor, String state, Map<String, Operation> operationByNodeIdExtras) { + @Deprecated + public void deserialize(IProgressMonitor monitor, String state, + Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> operationByNodeIdExtras) { + Map<String, Operation> operationByNodeId = new HashMap<String, Operation>(); + for (Entry<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> entry : operationByNodeIdExtras.entrySet()) { + org.eclipse.epp.internal.mpc.ui.wizards.Operation op = entry.getValue(); + operationByNodeId.put(entry.getKey(), op == null ? null : op.getOperation()); + } + deserialize(state, operationByNodeId, monitor); + } + + /** + * @param state + * the state to restore + * @param operationByNodeExtras + * additional operations to include + * @param monitor + */ + public void deserialize(String state, Map<String, Operation> operationByNodeExtras, IProgressMonitor monitor) { Map<String, Operation> operationByNodeId = new HashMap<String, Operation>(); if (state != null && state.length() > 0) { @@ -75,8 +97,8 @@ public class SelectionModelStateSerializer { operationByNodeId.put(nodeId, operation); } } - if (operationByNodeIdExtras != null) { - operationByNodeId.putAll(operationByNodeIdExtras); + if (operationByNodeExtras != null) { + operationByNodeId.putAll(operationByNodeExtras); } if (!operationByNodeId.isEmpty()) { catalog.performQuery(monitor, operationByNodeId.keySet()); @@ -86,7 +108,7 @@ public class SelectionModelStateSerializer { Operation operation = operationByNodeId.get(nodeItem.getData().getId()); if (operation != null && operation != Operation.NONE) { if (nodeItem.isInstalled() && operation == Operation.INSTALL) { - operation = Operation.CHECK_FOR_UPDATES; + operation = Operation.UPDATE; } selectionModel.select(nodeItem, operation); } @@ -95,7 +117,15 @@ public class SelectionModelStateSerializer { } } + /** + * @deprecated use {@link #deserialize(String, IProgressMonitor)} instead. + */ + @Deprecated public void deserialize(IProgressMonitor monitor, String state) { - deserialize(monitor, state, null); + deserialize(state, monitor); + } + + public void deserialize(String state, IProgressMonitor monitor) { + deserialize(state, null, monitor); } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ShareSolutionLink.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ShareSolutionLink.java index 694ec540..e5309705 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ShareSolutionLink.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/ShareSolutionLink.java @@ -7,6 +7,7 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.wizards; @@ -15,10 +16,10 @@ import java.lang.reflect.Method; import java.net.URI; import org.eclipse.core.runtime.URIUtil; -import org.eclipse.epp.internal.mpc.core.service.Node; import org.eclipse.epp.internal.mpc.core.util.TextUtil; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; +import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem; import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil; import org.eclipse.jface.dialogs.MessageDialog; @@ -139,7 +140,7 @@ public class ShareSolutionLink { } private String getUrl() { - return ((Node) catalogItem.getData()).getUrl(); + return ((INode) catalogItem.getData()).getUrl(); } private void openMail(URI uri) throws Exception { diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties index de6e83ba..b570e30d 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/internal/mpc/ui/wizards/messages.properties @@ -49,6 +49,8 @@ ItemButtonController_uninstallPending=Uninstall Pending ItemButtonController_update=Update ItemButtonController_updatePending=Update Pending MarketplaceBrowserIntegration_cannotOpenMarketplaceWizard=Cannot open Eclipse Marketplace +MarketplaceCatalogConfiguration_invalidStateObject=Invalid state object: {0} +MarketplaceClientService_noProvisioningOperation=No provisioning operations specified MarketplaceDropAdapter_0=Marketplace DND Initialization MarketplacePage_DefaultNewsTitle=News MarketplacePage_discardPendingSolutions=There are solutions pending for installation. Switching the marketplace will discard your selection. Proceed? @@ -81,6 +83,7 @@ NewsViewer_No_embeddable_browser=No embeddable Browser component was found for y NewsViewer_No_news=(No news available) Operation_install=install Operation_uninstall=uninstall +Operation_unknownOperation=Unknown operation: {0} Operation_update=update OverviewToolTip_cannotRenderImage_reason=Cannot render image {0}: {1} OverviewToolTip_learnMoreLink=<a>Learn more</a> diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/CatalogDescriptor.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/CatalogDescriptor.java index 33ad532c..97a93137 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/CatalogDescriptor.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/CatalogDescriptor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 The Eclipse Foundation and others. + * Copyright (c) 2010, 2014 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 v1.0 * which accompanies this distribution, and is available at @@ -7,18 +7,24 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.ui; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; +import org.eclipse.epp.mpc.core.model.ICatalog; +import org.eclipse.epp.mpc.core.model.ICatalogBranding; import org.eclipse.jface.resource.ImageDescriptor; /** * A descriptor for identifying a solutions catalog, ie: a location that implements the Eclipse Marketplace API. - * + * * @author David Green + * @see org.eclipse.epp.mpc.core.model.ICatalog * @see MarketplaceClient#addCatalogDescriptor(CatalogDescriptor) */ public final class CatalogDescriptor { @@ -30,6 +36,8 @@ public final class CatalogDescriptor { private ImageDescriptor icon; + private ICatalogBranding catalogBranding; + private boolean installFromAllRepositories; private URL dependenciesRepository; @@ -60,6 +68,21 @@ public final class CatalogDescriptor { this.installFromAllRepositories = catalogDescriptor.installFromAllRepositories; } + public CatalogDescriptor(ICatalog catalog) throws MalformedURLException { + setLabel(catalog.getName()); + setUrl(new URL(catalog.getUrl())); + setIcon(ImageDescriptor.createFromURL(new URL(catalog.getImageUrl()))); + setDescription(catalog.getDescription()); + setInstallFromAllRepositories(!catalog.isSelfContained()); + if (catalog.getDependencyRepository() != null) { + setDependenciesRepository(new URL(catalog.getDependencyRepository())); + } + setCatalogBranding(catalog.getBranding()); + if (catalog.getNews() != null) { + CatalogRegistry.getInstance().addCatalogNews(this, catalog.getNews()); + } + } + /** * The URL of the catalog. The URL identifies the catalog location, which provides an API described by <a * href="http://wiki.eclipse.org/Marketplace/REST">Marketplace REST</a> @@ -74,7 +97,7 @@ public final class CatalogDescriptor { /** * A description of the catalog, presented to the user. Should be brief (ie: one or two sentences). - * + * * @return the description or null if there is no description */ public String getDescription() { @@ -112,7 +135,7 @@ public final class CatalogDescriptor { * configuration. When false installation resolves only against repositories of the selected catalog items including * repositories considered as default for the catalog. Currently there is no way to define catalog default * repositories, however it is expected that this may change in the future. The default value is false. - * + * * @return true if installation occurs from all repositories, otherwise false. */ public boolean isInstallFromAllRepositories() { @@ -141,6 +164,20 @@ public final class CatalogDescriptor { this.dependenciesRepository = dependenciesRepository; } + /** + * Branding information controlling wizard title and icon and available tabs. + */ + public ICatalogBranding getCatalogBranding() { + return catalogBranding; + } + + /** + * @see #getCatalogBranding() + */ + public void setCatalogBranding(ICatalogBranding catalogBranding) { + this.catalogBranding = catalogBranding; + } + @Override public int hashCode() { final int prime = 31; @@ -190,5 +227,4 @@ public final class CatalogDescriptor { public String toString() { return "CatalogDescriptor [url=" + url + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } - } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientConfiguration.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientConfiguration.java new file mode 100644 index 00000000..c16e8de1 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientConfiguration.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, public API (bug 432803) + *******************************************************************************/ +package org.eclipse.epp.mpc.ui; + +import java.util.List; +import java.util.Map; + +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.epp.mpc.core.service.ICatalogService; + +/** + * Configuration for launching the Marketplace Wizard using {@link IMarketplaceClientService}. + * + * @see IMarketplaceClientService + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMarketplaceClientConfiguration { + /** + * @see #getCatalogDescriptors() + */ + void setCatalogDescriptors(List<CatalogDescriptor> descriptors); + + /** + * @see #getCatalogDescriptor() + */ + void setCatalogDescriptor(CatalogDescriptor initial); + + /** + * Valid objects for the initial state are only created by the marketplace wizard internally. Clients wishing to + * start the wizard in a defined state should refer to {@link #setInitialOperations(Map)} instead. + * + * @see #getInitialState() + */ + void setInitialState(Object state); + + /** + * @see #getInitialOperations() + */ + void setInitialOperations(Map<String, Operation> selection); + + /** + * The initial selection state applied to marketplace entries by {@link INode#getId() node id}. + */ + Map<String, Operation> getInitialOperations(); + + /** + * The initial state applied to the Wizard. This will be merged with any additional {@link #getInitialOperations() + * initial operations}. + * <p> + * This is used internally to suspend and resume the wizard, e.g. to switch to an embedded web browser to show + * marketplace pages. + * <p> + * Valid objects for the initial state are only created by the marketplace wizard internally. Clients wishing to + * start the wizard in a defined state should refer to {@link #setInitialOperations(Map)} instead. + */ + Object getInitialState(); + + /** + * The initially active catalog. By default, either the last active catalog from a previous launch or the first + * {@link #setCatalogDescriptors(List) available catalog} will be selected. + */ + CatalogDescriptor getCatalogDescriptor(); + + /** + * The list of available Marketplace catalogs. These will be shown in the wizard's catalog selector. If no + * descriptors are set explicitly, a default list will be retrieved using the {@link ICatalogService}. + */ + List<CatalogDescriptor> getCatalogDescriptors(); +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java new file mode 100644 index 00000000..fbcdcee5 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/IMarketplaceClientService.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Yatta Solutions - initial API and implementation, public API (bug 432803) + *******************************************************************************/ +package org.eclipse.epp.mpc.ui; + +import java.util.Set; + +import org.eclipse.epp.mpc.core.model.ICategory; +import org.eclipse.epp.mpc.core.model.IMarket; +import org.eclipse.epp.mpc.core.model.INode; + +/** + * This service allows opening the Eclipse Marketplace Wizard in a predefined state, e.g. to show a specific search, + * preselected items, or start the install of selected nodes. + * <p> + * An instance of this class can be acquired as an OSGi service or through the {@link MarketplaceClient} + * {@link MarketplaceClient#getMarketplaceClientService() convenience method}. + * + * @author Carsten Reckord + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMarketplaceClientService { + /** + * @return an editable configuration object for the Marketplace Wizard + */ + IMarketplaceClientConfiguration newConfiguration(); + + /** + * Open the Marketplace Wizard using the given configuration. Regardless of an + * {@link IMarketplaceClientConfiguration#setInitialOperations(java.util.Map) initial selection} defined in the + * configuration, this will always launch the wizard on the initial catalog page. + * + * @param configuration + * the initial configuration applied to the MPC wizard + */ + void open(IMarketplaceClientConfiguration configuration); + + /** + * Open the Marketplace Wizard showing the + * {@link IMarketplaceClientConfiguration#setInitialOperations(java.util.Map) initial selection} defined in the + * configuration. + * + * @param configuration + * the initial configuration applied to the MPC wizard + * @throws IllegalArgumentException + * if the configuration does not contain an initial selection either in + * {@link IMarketplaceClientConfiguration#getInitialOperations()} or + * {@link IMarketplaceClientConfiguration#getInitialState()} + */ + void openSelected(IMarketplaceClientConfiguration configuration); + + /** + * Open the Marketplace Wizard showing the "Installed" tab for the + * {@link IMarketplaceClientConfiguration#getCatalogDescriptor() active catalog}. + * + * @param configuration + * the initial configuration applied to the MPC wizard + */ + void openInstalled(IMarketplaceClientConfiguration configuration); + + /** + * Open the Marketplace Wizard showing the result of the given search on the + * {@link IMarketplaceClientConfiguration#getCatalogDescriptor() active catalog}. + * + * @param configuration + * the initial configuration applied to the MPC wizard + * @param market + * the market to search in or null to search in all markets + * @param category + * the category to search in or null to search in all categories + * @param query + * the search terms + */ + void openSearch(IMarketplaceClientConfiguration configuration, IMarket market, ICategory category, String query); + + /** + * Open the Marketplace Wizard showing the given list of nodes in the MPC's search view. + * + * @param configuration + * the initial configuration applied to the MPC wizard + * @param nodes + * the nodes to show + */ + void open(IMarketplaceClientConfiguration configuration, Set<INode> nodes); + + /** + * Trigger the specified {@link IMarketplaceClientConfiguration#getInitialOperations() provisioning operations} in + * the Marketplace Wizard. This will launch the Wizard on the feature selection page, as if selecting the respective + * operations on the catalog page and clicking "Install Now" afterwards. + * + * @param configuration + * the initial configuration applied to the MPC wizard + * @throws IllegalArgumentException + * if the configuration does not contain an initial selection either in + * {@link IMarketplaceClientConfiguration#getInitialOperations()} or + * {@link IMarketplaceClientConfiguration#getInitialState()} + */ + void openProvisioning(IMarketplaceClientConfiguration configuration); + +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceClient.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceClient.java index fc9fd301..97e107dc 100644 --- a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceClient.java +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceClient.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 The Eclipse Foundation and others. + * Copyright (c) 2010, 2014 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 v1.0 * which accompanies this distribution, and is available at @@ -7,25 +7,26 @@ * * Contributors: * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API *******************************************************************************/ package org.eclipse.epp.mpc.ui; import java.util.List; -import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; -import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; +import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; /** * Provides a means to configure and launch the marketplace client. - * + * * @author David Green + * @author Carsten Reckord */ public class MarketplaceClient { /** * Add a catalog descriptor to those available to be the user when accessing the marketplace. - * + * * @param catalogDescriptor * the descriptor, must not be null * @see #removeCatalogDescriptor(CatalogDescriptor) @@ -39,7 +40,7 @@ public class MarketplaceClient { /** * Remove a catalog descriptor from those available to the user when accessing the marketplace. - * + * * @see #addCatalogDescriptor(CatalogDescriptor) */ public static void removeCatalogDescriptor(CatalogDescriptor catalogDescriptor) { @@ -56,7 +57,7 @@ public class MarketplaceClient { * Upon return of this method the UI will have been displayed, however any provisioning operations instigated by the * user may not have completed. * </p> - * + * * @param catalogDescriptors * the catalogs to query, or null if the default catalogs should be used. * @throws IllegalArgumentException @@ -79,9 +80,21 @@ public class MarketplaceClient { } } } - MarketplaceWizardCommand command = new MarketplaceWizardCommand(); - command.setCatalogDescriptors(catalogDescriptors); + IMarketplaceClientService clientService = getMarketplaceClientService(); + IMarketplaceClientConfiguration config = clientService.newConfiguration(); + if (catalogDescriptors != null) { + config.setCatalogDescriptors(catalogDescriptors); + } + clientService.open(config); + } - command.execute(new ExecutionEvent()); + /** + * Convenience method to retrieve a registered {@link IMarketplaceClientService client service} for opening the MPC + * wizard dialog. + * + * @return a client service from the OSGi service registry + */ + public static IMarketplaceClientService getMarketplaceClientService() { + return MarketplaceClientUiPlugin.getInstance().getClientService(); } } diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java new file mode 100644 index 00000000..853325b8 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/MarketplaceUrlHandler.java @@ -0,0 +1,441 @@ +/******************************************************************************* + * Copyright (c) 2011 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + * Yatta Solutions - news (bug 401721), public API (bug 432803) + *******************************************************************************/ +package org.eclipse.epp.mpc.ui; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; +import org.eclipse.epp.internal.mpc.core.service.Node; +import org.eclipse.epp.internal.mpc.ui.CatalogRegistry; +import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi; +import org.eclipse.epp.internal.mpc.ui.commands.MarketplaceWizardCommand; +import org.eclipse.epp.mpc.core.model.INode; +import org.eclipse.osgi.util.NLS; +import org.eclipse.ui.statushandlers.StatusManager; + +/** + * Handler for Marketplace URLs. It supports parsing of Marketplace-related URLs through its {@link #handleUri(String)} + * method and will call the appropriate <code>handleXXX</code> methods depending on the URL. Clients can override the + * methods they wish to handle. Default behavior for handle methods is to do nothing unless specified otherwise on the + * handler method. + * + * @author David Green + * @author Benjamin Muskalla + * @author Carsten Reckord + */ +public abstract class MarketplaceUrlHandler { + + public static final String DESCRIPTOR_HINT = "org.eclipse.epp.mpc.descriptorHint"; //$NON-NLS-1$ + + public static final String MPC_INSTALL_URI = "/mpc/install?"; //$NON-NLS-1$ + + public static final String SITE_SEARCH_URI = "/search/site"; //$NON-NLS-1$ + + private static final Pattern CONTENT_URL_PATTERN = Pattern.compile("(?:^|/)content/([^/#?]+)"); //$NON-NLS-1$ + + private static final Pattern NODE_URL_PATTERN = Pattern.compile("(?:^|/)node/([^/#?]+)"); //$NON-NLS-1$ + + public static class SolutionInstallationInfo { + + private String requestUrl; + + private String installId; + + private String state; + + private CatalogDescriptor catalogDescriptor; + + public SolutionInstallationInfo() { + } + + protected SolutionInstallationInfo(String installId, String state, CatalogDescriptor catalogDescriptor) { + super(); + this.installId = installId; + this.state = state; + this.catalogDescriptor = catalogDescriptor; + } + + public String getInstallId() { + return installId; + } + + public String getState() { + return state; + } + + public CatalogDescriptor getCatalogDescriptor() { + return catalogDescriptor; + } + + public void setRequestUrl(String requestUrl) { + this.requestUrl = requestUrl; + } + + public String getRequestUrl() { + return requestUrl; + } + } + + protected static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ + + private static final String PARAM_SPLIT_REGEX = "&"; //$NON-NLS-1$ + + private static final String EQUALS_REGEX = "="; //$NON-NLS-1$ + + private static final String MPC_STATE = "mpc_state"; //$NON-NLS-1$ + + private static final String MPC_INSTALL = "mpc_install"; //$NON-NLS-1$ + + public static SolutionInstallationInfo createSolutionInstallInfo(String url) { + String installId = null; + String state = null; + Map<String, String> query = parseQuery(url); + if (query != null) { + installId = query.get(MPC_INSTALL); + state = query.get(MPC_STATE); + } + if (installId != null) { + CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(url); + if (descriptor == null) { + try { + descriptor = new CatalogDescriptor(new URL(url), DESCRIPTOR_HINT); + } catch (MalformedURLException e) { + return null; + } + } + SolutionInstallationInfo info = new SolutionInstallationInfo(installId, state, descriptor); + info.setRequestUrl(url); + return info; + } + return null; + } + + public static String getMPCState(String url) { + Map<String, String> query = parseQuery(url); + return query == null ? null : query.get(MPC_STATE); + } + + private static Map<String, String> parseQuery(String url) { + String query; + try { + query = new URL(url).getQuery(); + } catch (MalformedURLException e) { + return null; + } + if (query == null) { + return null; + } + Map<String, String> values = new LinkedHashMap<String, String>(); + String[] params = query.split(PARAM_SPLIT_REGEX); + for (String param : params) { + String[] keyValue = param.split(EQUALS_REGEX); + if (keyValue.length == 2) { + String key = keyValue[0]; + String value = keyValue[1]; + values.put(key, value); + } + } + return values; + } + + public static boolean isPotentialSolution(String url) { + return url != null && url.contains(MPC_INSTALL); + } + + public static void triggerInstall(SolutionInstallationInfo info) { + if (info.getRequestUrl() != null) { + MarketplaceClientUi.getLog().log( + new Status(IStatus.INFO, MarketplaceClientUi.BUNDLE_ID, NLS.bind( + Messages.MarketplaceUrlHandler_performInstallRequest, info.getRequestUrl()))); + } + String installId = info.getInstallId(); + String mpcState = info.getState(); + CatalogDescriptor catalogDescriptor = info.getCatalogDescriptor(); + MarketplaceWizardCommand command = new MarketplaceWizardCommand(); + command.setSelectedCatalogDescriptor(catalogDescriptor); + try { + if (mpcState != null) { + command.setWizardState(URLDecoder.decode(mpcState, UTF_8)); + } + Map<String, Operation> nodeToOperation = new HashMap<String, Operation>(); + nodeToOperation.put(URLDecoder.decode(installId, UTF_8), Operation.INSTALL); + command.setOperations(nodeToOperation); + } catch (UnsupportedEncodingException e1) { + throw new IllegalStateException(e1); + } + try { + command.execute(new ExecutionEvent()); + } catch (ExecutionException e) { + IStatus status = MarketplaceClientUi.computeStatus(e, + Messages.MarketplaceUrlHandler_cannotOpenMarketplaceWizard); + StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); + } + } + + public boolean handleUri(String uri) { + if (isPotentialSolution(uri)) { + SolutionInstallationInfo installInfo = createSolutionInstallInfo(uri); + if (installInfo != null) { + return handleInstallRequest(installInfo, uri); + } + } + + CatalogDescriptor descriptor = CatalogRegistry.getInstance().findCatalogDescriptor(uri); + if (descriptor == null) { + descriptor = handleUnknownCatalog(uri); + if (descriptor == null) { + return false; + } + } + + String baseUri; + try { + baseUri = descriptor.getUrl().toURI().toString(); + if (!baseUri.endsWith("/")) { //$NON-NLS-1$ + baseUri += '/'; + } + } catch (URISyntaxException e) { + // should be unreachable + throw new IllegalStateException(e); + } + + if (!uri.startsWith(baseUri)) { + uri = resolve(uri, baseUri, descriptor); + if (!uri.startsWith(baseUri)) { + return false; + } + } + String relativeUri = uri.substring(baseUri.length()); + if (relativeUri.startsWith(DefaultMarketplaceService.API_FAVORITES_URI)) { + return handleFavorites(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_FEATURED_URI)) { + return handleFeatured(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_NODE_CONTENT_URI)) { + return handleNodeContent(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_NODE_URI)) { + return handleNode(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_POPULAR_URI)) { + return handlePopular(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_RECENT_URI)) { + return handleRecent(descriptor, relativeUri); + } else if (relativeUri.startsWith(DefaultMarketplaceService.API_SEARCH_URI) + || relativeUri.startsWith(DefaultMarketplaceService.API_SEARCH_URI_FULL)) { + return handleSolrSearch(descriptor, relativeUri); + } else if (relativeUri.startsWith(SITE_SEARCH_URI.substring(1))) { + return handleSiteSearch(descriptor, relativeUri); + } else { + return handleUnknownPath(descriptor, relativeUri); + } + } + + /** + * Resolve the given URL against the catalog's base URI. The default implementation changes the HTTP/HTTPS schema to + * match the catalog URI. + */ + protected String resolve(String url, String baseUri, CatalogDescriptor descriptor) { + if (url.startsWith("https:") && baseUri.startsWith("http:")) { //$NON-NLS-1$ //$NON-NLS-2$ + url = "http:" + url.substring("https:".length()); //$NON-NLS-1$ //$NON-NLS-2$ + } else if (url.startsWith("http:") && baseUri.startsWith("https:")) { //$NON-NLS-1$ //$NON-NLS-2$ + url = "https:" + url.substring("http:".length()); //$NON-NLS-1$ //$NON-NLS-2$ + } + return url; + } + + protected boolean handleUnknownPath(CatalogDescriptor descriptor, String url) { + return false; + } + + private boolean handleSolrSearch(CatalogDescriptor descriptor, String url) { + try { + Map<String, String> params = new HashMap<String, String>(); + String searchString = parseSearchQuery(descriptor, url, params); + return handleSearch(descriptor, url, searchString, params); + } catch (MalformedURLException e) { + // don't handle malformed URLs + return false; + } catch (URISyntaxException e) { + // don't handle malformed URLs + return false; + } + } + + private boolean handleSiteSearch(CatalogDescriptor descriptor, String url) { + try { + Map<String, String> params = new HashMap<String, String>(); + String searchString = parseSearchQuery(descriptor, url, params); + + // convert queries of this format + // f[0]=im_taxonomy_vocabulary_1:38&f[1]=im_taxonomy_vocabulary_3:31 + // to internal solr format + // filter=tid:38 tid:31 + StringBuilder filter = new StringBuilder(); + for (Iterator<String> i = params.values().iterator(); i.hasNext();) { + String str = i.next(); + if (str.startsWith("im_taxonomy_vocabulary_")) { //$NON-NLS-1$ + int sep = str.indexOf(':'); + if (sep != -1) { + String tid = str.substring(sep + 1); + if (filter.length() > 0) { + filter.append(' '); + } + filter.append(tid); + i.remove(); + } + } + } + return handleSearch(descriptor, url, searchString, params); + } catch (MalformedURLException e) { + // don't handle malformed URLs + return false; + } catch (URISyntaxException e) { + // don't handle malformed URLs + return false; + } + } + + private String parseSearchQuery(CatalogDescriptor descriptor, String url, Map<String, String> params) + throws URISyntaxException, MalformedURLException { + URI searchUri = new URL(descriptor.getUrl(), url).toURI(); + String path = searchUri.getPath(); + if (path.endsWith("/")) { //$NON-NLS-1$ + path = path.substring(0, path.length() - 1); + } + int sep = path.lastIndexOf('/'); + String searchString = path.substring(sep + 1); + String query = searchUri.getQuery(); + if (query != null) { + extractParams(query, params); + } + return searchString; + } + + protected boolean handleSearch(CatalogDescriptor descriptor, String url, String searchString, + Map<String, String> params) { + return false; + } + + private void extractParams(String query, Map<String, String> params) { + final String[] paramStrings = query.split("&"); //$NON-NLS-1$ + for (String param : paramStrings) { + final String[] parts = param.split("="); //$NON-NLS-1$ + if (parts.length == 2) { + params.put(parts[0], parts[1]); + } + } + } + + protected boolean handleRecent(CatalogDescriptor descriptor, String url) { + return false; + } + + protected boolean handlePopular(CatalogDescriptor descriptor, String url) { + return false; + } + + private boolean handleNode(CatalogDescriptor descriptor, String url) { + Matcher matcher = NODE_URL_PATTERN.matcher(url); + String id = null; + if (matcher.find()) { + id = matcher.group(1); + } + Node node = new Node(); + node.setId(id); + return handleNode(descriptor, url, node); + } + + private boolean handleNodeContent(CatalogDescriptor descriptor, String url) { + Matcher matcher = CONTENT_URL_PATTERN.matcher(url); + String title = null; + if (matcher.find()) { + title = matcher.group(1); + } + Node node = new Node(); + node.setUrl(url); + if (title != null) { + String base = descriptor.getUrl().toExternalForm(); + if (!base.endsWith("/")) { //$NON-NLS-1$ + base += "/"; //$NON-NLS-1$ + } + int titleEnd = matcher.end(); + if (titleEnd > -1) { + //clean the url of other query parameters + node.setUrl(base + url.substring(0, titleEnd)); + } else { + //unknown format, leave as-is + node.setUrl(base + url); + } + } + return handleNode(descriptor, url, node); + } + + protected boolean handleNode(CatalogDescriptor descriptor, String url, INode node) { + return false; + } + + private boolean handleFeatured(CatalogDescriptor descriptor, String url) { + Matcher matcher = Pattern.compile("(?:^|/)featured/(\\d+)(?:,(\\d+))?").matcher(url); //$NON-NLS-1$ + String cat = null; + String market = null; + if (matcher.find()) { + cat = matcher.group(1); + if (matcher.groupCount() > 1) { + market = matcher.group(2); + } + } + return handleFeatured(descriptor, url, cat, market); + } + + protected boolean handleFeatured(CatalogDescriptor descriptor, String url, String category, String market) { + return false; + } + + protected boolean handleFavorites(CatalogDescriptor descriptor, String url) { + return false; + } + + /** + * Called if no known {@link CatalogDescriptor} is registered for the given URL. Clients may override to return a + * custom {@link CatalogDescriptor} or to perform additional lookup of registered catalogs. + * <p> + * The default implementation looks for catalogs registered for the same host but a different schema - if the url + * uses http, a catalog with an equivalent https url is searched and vice versa. + */ + protected CatalogDescriptor handleUnknownCatalog(String url) { + if (url.startsWith("https:")) { //$NON-NLS-1$ + url = "http:" + url.substring("https:".length()); //$NON-NLS-1$ //$NON-NLS-2$ + return CatalogRegistry.getInstance().findCatalogDescriptor(url); + } else if (url.startsWith("http:")) { //$NON-NLS-1$ + url = "https:" + url.substring("http:".length()); //$NON-NLS-1$ //$NON-NLS-2$ + return CatalogRegistry.getInstance().findCatalogDescriptor(url); + } + return null; + } + + protected boolean handleInstallRequest(SolutionInstallationInfo installInfo, String url) { + return false; + } +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Messages.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Messages.java new file mode 100644 index 00000000..b37c0384 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Messages.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + *******************************************************************************/ +package org.eclipse.epp.mpc.ui; + +import org.eclipse.osgi.util.NLS; + +class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.epp.mpc.ui.messages"; //$NON-NLS-1$ + + public static String MarketplaceUrlHandler_cannotOpenMarketplaceWizard; + + public static String MarketplaceUrlHandler_performInstallRequest; + + public static String Operation_install; + + public static String Operation_uninstall; + + public static String Operation_update; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Operation.java b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Operation.java new file mode 100644 index 00000000..a9578601 --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/Operation.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + * Yatta Solutions - bug 432803: public API + *******************************************************************************/ +package org.eclipse.epp.mpc.ui; + + +/** + * Represents kinds of provisioning operations supported by the wizard + */ +public enum Operation { + INSTALL(Messages.Operation_install), // + UNINSTALL(Messages.Operation_uninstall), // + UPDATE(Messages.Operation_update), // + NONE(null); + + private final String label; + + private Operation(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/messages.properties b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/messages.properties new file mode 100644 index 00000000..9a977dbd --- /dev/null +++ b/org.eclipse.epp.mpc.ui/src/org/eclipse/epp/mpc/ui/messages.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2014 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 v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# The Eclipse Foundation - initial API and implementation +############################################################################### +MarketplaceUrlHandler_cannotOpenMarketplaceWizard=Cannot open Eclipse Marketplace +MarketplaceUrlHandler_performInstallRequest=Performing Marketplace install request from {0} +Operation_install=install +Operation_uninstall=uninstall +Operation_update=update |