diff options
| author | Carsten Reckord | 2020-08-10 15:49:12 +0000 |
|---|---|---|
| committer | Carsten Reckord | 2020-09-01 17:13:48 +0000 |
| commit | 0d8562954756146de11cdd9a55fe37269bfad1e1 (patch) | |
| tree | e0952b1dd7db977a6a2ba758d90708407b38c6d0 | |
| parent | ff00246e18c568b4b7738581eabfd89e2caff27c (diff) | |
| download | org.eclipse.epp.mpc-0d8562954756146de11cdd9a55fe37269bfad1e1.tar.gz org.eclipse.epp.mpc-0d8562954756146de11cdd9a55fe37269bfad1e1.tar.xz org.eclipse.epp.mpc-0d8562954756146de11cdd9a55fe37269bfad1e1.zip | |
Bug 560084: Improve startup up time of Marketplace client
Refactored HTTP and Transport layer initialization. Everything is lazy
and service-based now.
Change-Id: Idb30512068932c87f905dfaf299ac7db5bec7662
Signed-off-by: Carsten Reckord <reckord@yatta.de>
39 files changed, 1051 insertions, 1018 deletions
diff --git a/org.eclipse.epp.mpc-target/staging.target b/org.eclipse.epp.mpc-target/staging.target index 8cc4d20e..346b455c 100644 --- a/org.eclipse.epp.mpc-target/staging.target +++ b/org.eclipse.epp.mpc-target/staging.target @@ -16,7 +16,7 @@ <unit id="org.hamcrest.library" version="0.0.0"/> <unit id="org.junit" version="0.0.0"/> <unit id="org.mockito" version="0.0.0"/> -<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20200128200239/repository"/> +<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20200826182026/repository"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit"> <unit id="org.eclipse.epp.mpc.apache.httpclient.feature.feature.group" version="0.0.0"/> diff --git a/org.eclipse.epp.mpc.core/.settings/org.eclipse.pde.ds.annotations.prefs b/org.eclipse.epp.mpc.core/.settings/org.eclipse.pde.ds.annotations.prefs new file mode 100644 index 00000000..9eb1c5f3 --- /dev/null +++ b/org.eclipse.epp.mpc.core/.settings/org.eclipse.pde.ds.annotations.prefs @@ -0,0 +1,8 @@ +classpath=true
+dsVersion=V1_3
+eclipse.preferences.version=1
+enabled=true
+generateBundleActivationPolicyLazy=true
+path=OSGI-INF/services
+validationErrorLevel=error
+validationErrorLevel.missingImplicitUnbindMethod=error
diff --git a/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF b/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF index 0f29415a..08c87dad 100644 --- a/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF +++ b/org.eclipse.epp.mpc.core/META-INF/MANIFEST.MF @@ -62,7 +62,6 @@ Import-Package: org.apache.http;version="4.4.0", org.apache.http.client;version="4.5.2", org.apache.http.client.config;version="4.5.2", org.apache.http.client.entity;version="4.5.2", - org.apache.http.client.fluent;version="4.5.2", org.apache.http.client.methods;version="4.5.2", org.apache.http.client.protocol;version="4.5.2", org.apache.http.config;version="4.4.0", diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-transport.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-transport.xml deleted file mode 100644 index bb17fe43..00000000 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-transport.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014, 2018 The Eclipse Foundation and others.
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v2.0
- which accompanies this distribution, and is available at
- https://www.eclipse.org/legal/epl-2.0/
- - SPDX-License-Identifier: EPL-2.0 -
- Contributors:
- The Eclipse Foundation - initial API and implementation
- -->
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.core.transport.http">
- <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport"/>
- <service>
- <provide interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport"/>
- </service>
-</scr:component>
diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-wrapper-factory.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-wrapper-factory.xml index 3e11f5fe..efe2a3b0 100644 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-wrapper-factory.xml +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-wrapper-factory.xml @@ -17,4 +17,5 @@ <provide interface="org.eclipse.epp.mpc.core.service.ITransportFactory"/>
</service>
<reference bind="bindPrimaryFactory" cardinality="1..1" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransportFactory" name="org.eclipse.epp.mpc.core.transport.http.factory" policy="static" unbind="unbindPrimaryFactory"/>
+ <property name="service.ranking" type="Integer" value="1"/>
</scr:component>
diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/legacy-transport-factory.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/legacy-transport-factory.xml deleted file mode 100644 index 307fd431..00000000 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/legacy-transport-factory.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014, 2018 The Eclipse Foundation and others.
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v2.0
- which accompanies this distribution, and is available at
- https://www.eclipse.org/legal/epl-2.0/
- - SPDX-License-Identifier: EPL-2.0 -
- Contributors:
- The Eclipse Foundation - initial API and implementation
- -->
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.core.transportfactory.legacy">
- <implementation class="org.eclipse.epp.internal.mpc.core.util.TransportFactory$LegacyFactory"/>
- <service>
- <provide interface="org.eclipse.epp.mpc.core.service.ITransportFactory"/>
- </service>
- <property name="org.eclipse.epp.mpc.core.service.transport.legacy" type="Boolean" value="true"/>
- <property name="service.ranking" type="Integer" value="-2147483647"/>
-</scr:component>
diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.debug.options.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.debug.options.xml new file mode 100644 index 00000000..f4fc55d5 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.debug.options.xml @@ -0,0 +1,8 @@ +<?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.core.debug.options">
+ <property name="listener.symbolic.name" value="org.eclipse.epp.mpc.core"/>
+ <service>
+ <provide interface="org.eclipse.osgi.service.debug.DebugOptionsListener"/>
+ </service>
+ <implementation class="org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin$DebugOptionsInitializer"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.factory.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.factory.xml new file mode 100644 index 00000000..933ce783 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.factory.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" name="org.eclipse.epp.mpc.core.http.client.factory">
+ <service>
+ <provide interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientFactory"/>
+ </service>
+ <reference cardinality="0..n" field="customizers" field-option="replace" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientCustomizer" name="customizers" policy="static" policy-option="greedy"/>
+ <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientFactory"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.xml new file mode 100644 index 00000000..304d506b --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.http.client.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" name="org.eclipse.epp.mpc.core.http.client">
+ <service>
+ <provide interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService"/>
+ </service>
+ <reference bind="bindClientFactory" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientFactory" name="ClientFactory" policy="dynamic" policy-option="greedy" unbind="unbindClientFactory" updated="bindClientFactory"/>
+ <reference bind="bindProxyService" field="proxyService" interface="org.eclipse.core.net.proxy.IProxyService" name="ProxyService" policy="dynamic" unbind="unbindProxyService"/>
+ <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicehelper.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicehelper.xml new file mode 100644 index 00000000..df38a1e4 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicehelper.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="org.eclipse.epp.mpc.core.servicehelper">
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.ServiceHelper"/>
+ <provide interface="org.eclipse.epp.internal.mpc.core.ServiceHelperImpl"/>
+ </service>
+ <implementation class="org.eclipse.epp.internal.mpc.core.ServiceHelperImpl"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicelocator.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicelocator.xml new file mode 100644 index 00000000..4ea9d38a --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.servicelocator.xml @@ -0,0 +1,8 @@ +<?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.core.servicelocator">
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.IMarketplaceServiceLocator"/>
+ </service>
+ <reference bind="bindHttpClient" cardinality="1..1" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService" name="HttpClient" policy="dynamic" unbind="unbindHttpClient"/>
+ <implementation class="org.eclipse.epp.internal.mpc.core.ServiceLocator"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-transport-factory.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transport.http.factory.xml index bf0ff9e3..2c295748 100644 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/httpclient-transport-factory.xml +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transport.http.factory.xml @@ -1,20 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014, 2018 The Eclipse Foundation and others.
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v2.0
- which accompanies this distribution, and is available at
- https://www.eclipse.org/legal/epl-2.0/
- - SPDX-License-Identifier: EPL-2.0 -
- Contributors:
- The Eclipse Foundation - initial API and implementation
- -->
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.epp.mpc.core.transport.http.factory">
- <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransportFactory"/>
<service>
<provide interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransportFactory"/>
+ <provide interface="org.eclipse.epp.mpc.core.service.ITransportFactory"/>
</service>
<reference bind="bindTransport" cardinality="1..1" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport" name="org.eclipse.epp.mpc.core.transport.http" policy="static" unbind="unbindTransport"/>
-</scr:component>
+ <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransportFactory"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transport.http.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transport.http.xml new file mode 100644 index 00000000..b21c3d1d --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transport.http.xml @@ -0,0 +1,9 @@ +<?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.core.transport.http">
+ <service>
+ <provide interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport"/>
+ <provide interface="org.eclipse.epp.mpc.core.service.ITransport"/>
+ </service>
+ <reference bind="bindHttpClientService" interface="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService" name="HttpClientService"/>
+ <implementation class="org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transportfactory.legacy.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transportfactory.legacy.xml new file mode 100644 index 00000000..3cc48af0 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.transportfactory.legacy.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="org.eclipse.epp.mpc.core.transportfactory.legacy">
+ <property name="org.eclipse.epp.mpc.core.service.transport.legacy" type="Boolean" value="true"/>
+ <property name="service.ranking" type="Integer" value="-2147483647"/>
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.ITransportFactory"/>
+ </service>
+ <implementation class="org.eclipse.epp.internal.mpc.core.util.TransportFactory$LegacyFactory"/>
+</scr:component>
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.unmarshaller.xml b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.unmarshaller.xml new file mode 100644 index 00000000..79f8e914 --- /dev/null +++ b/org.eclipse.epp.mpc.core/OSGI-INF/services/org.eclipse.epp.mpc.core.unmarshaller.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.core.unmarshaller">
+ <service>
+ <provide interface="org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller"/>
+ </service>
+ <implementation class="org.eclipse.epp.internal.mpc.core.service.MarketplaceUnmarshaller"/>
+</scr:component>
\ No newline at end of file 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 deleted file mode 100644 index 85127228..00000000 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/service-locator.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014, 2018 The Eclipse Foundation and others.
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v2.0
- which accompanies this distribution, and is available at
- https://www.eclipse.org/legal/epl-2.0/
- - SPDX-License-Identifier: EPL-2.0 -
- Contributors:
- The Eclipse Foundation - initial API and implementation
- -->
-<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 deleted file mode 100644 index d3f8a5e5..00000000 --- a/org.eclipse.epp.mpc.core/OSGI-INF/services/unmarshaller.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014, 2018 The Eclipse Foundation and others.
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v2.0
- which accompanies this distribution, and is available at
- https://www.eclipse.org/legal/epl-2.0/
- - SPDX-License-Identifier: EPL-2.0 -
- Contributors:
- The Eclipse Foundation - initial API and implementation
- -->
-<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/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 d51b2129..5c7f2ccc 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 @@ -13,25 +13,14 @@ *******************************************************************************/ package org.eclipse.epp.internal.mpc.core; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Hashtable; -import java.util.List; - import org.eclipse.epp.internal.mpc.core.util.DebugTraceUtil; -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.eclipse.osgi.service.debug.DebugOptions; import org.eclipse.osgi.service.debug.DebugOptionsListener; import org.eclipse.osgi.service.debug.DebugTrace; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.ComponentConstants; +import org.osgi.service.component.annotations.Component; public class MarketplaceClientCorePlugin implements BundleActivator { @@ -53,106 +42,24 @@ public class MarketplaceClientCorePlugin implements BundleActivator { private Bundle bundle; - private List<ServiceRegistration<?>> serviceRegistrations; - - private ServiceHelperImpl serviceHelper; - @Override public void start(BundleContext context) throws Exception { bundle = context.getBundle(); instance = this; - ProxyHelper.acquireProxyService(); - registerServices(context); - serviceHelper = new ServiceHelperImpl(); - serviceHelper.startTracking(context); - - Hashtable<String, String> props = new Hashtable<>(2); - props.put(org.eclipse.osgi.service.debug.DebugOptions.LISTENER_SYMBOLICNAME, MarketplaceClientCore.BUNDLE_ID); - context.registerService(DebugOptionsListener.class.getName(), (DebugOptionsListener) options -> { - DebugTrace debugTrace = null; - boolean debug = options.getBooleanOption(MarketplaceClientCore.BUNDLE_ID + DEBUG_OPTION, false); - boolean fakeClient = false; - if (debug) { - debugTrace = options.newDebugTrace(MarketplaceClientCore.BUNDLE_ID); - fakeClient = options.getBooleanOption(MarketplaceClientCore.BUNDLE_ID + DEBUG_FAKE_CLIENT_OPTION, - false); - } - DEBUG = debug; - DEBUG_FAKE_CLIENT = fakeClient; - MarketplaceClientCorePlugin.debugTrace = debugTrace; - }, props); } @Override public void stop(BundleContext context) throws Exception { - serviceHelper.stopTracking(context); - serviceHelper = null; - unregisterServices(); - ProxyHelper.releaseProxyService(); debugTrace = null; instance = null; } - private void registerServices(BundleContext context) throws InvalidSyntaxException { - List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<>(); - this.serviceRegistrations = serviceRegistrations; - - List<ITransportFactory> factories = TransportFactory.listAvailableFactories();//highest-prio factory comes first - if (factories.isEmpty()) { - return; - } - - Collection<ServiceReference<ITransportFactory>> serviceReferences = context - .getServiceReferences(ITransportFactory.class, null); - int lowestPriority = Integer.MAX_VALUE; - for (ServiceReference<ITransportFactory> serviceReference : serviceReferences) { - Object legacyProperty = serviceReference.getProperty(TransportFactory.LEGACY_TRANSPORT_KEY); - if (legacyProperty != null) { - continue; - } - Integer ranking = (Integer) serviceReference.getProperty(Constants.SERVICE_RANKING); - lowestPriority = Math.min(lowestPriority, ranking == null ? 0 : ranking.intValue()); - } - - int maxLegacyPriority, step; - if (lowestPriority >= 0) { - maxLegacyPriority = -100; - step = 100; - } else { - int available = lowestPriority - Integer.MIN_VALUE; - step = Math.min(100, available / factories.size()); - if (step == 0) { - step = 1; - maxLegacyPriority = Integer.MIN_VALUE + factories.size(); - } else { - maxLegacyPriority = lowestPriority - step; - } - } - int prio = maxLegacyPriority;//prio counts down from 0 in steps of 100 - for (ITransportFactory factory : factories) { - Hashtable<String, Object> properties = new Hashtable<>(); - properties.put(Constants.SERVICE_RANKING, prio); - properties.put(ComponentConstants.COMPONENT_NAME, "legacy:" + factory.getClass().getName()); - properties.put(TransportFactory.LEGACY_TRANSPORT_KEY, true); - ServiceRegistration<ITransportFactory> registration = context.registerService(ITransportFactory.class, - factory, properties); - serviceRegistrations.add(registration); - prio -= step; - } - } - - private void unregisterServices() { - List<ServiceRegistration<?>> serviceRegistrations = this.serviceRegistrations; - this.serviceRegistrations = null; - if (serviceRegistrations != null) { - for (ServiceRegistration<?> serviceRegistration : serviceRegistrations) { - serviceRegistration.unregister(); - } - } - } - + /** + * @deprecated Inject ServiceHelper as a service instead + */ + @Deprecated public ServiceHelperImpl getServiceHelper() { - return serviceHelper; + return ServiceHelperImpl.getImplInstance(); } public static MarketplaceClientCorePlugin getDefault() { @@ -176,4 +83,25 @@ public class MarketplaceClientCorePlugin implements BundleActivator { DebugTraceUtil.trace(trace, option, message, parameters); } } + + @Component(name = "org.eclipse.epp.mpc.core.debug.options", property = { + "listener.symbolic.name=org.eclipse.epp.mpc.core" }) + public static class DebugOptionsInitializer implements DebugOptionsListener { + + @Override + public void optionsChanged(DebugOptions options) { + DebugTrace debugTrace = null; + boolean debug = options.getBooleanOption(MarketplaceClientCore.BUNDLE_ID + DEBUG_OPTION, false); + boolean fakeClient = false; + if (debug) { + debugTrace = options.newDebugTrace(MarketplaceClientCore.BUNDLE_ID); + fakeClient = options.getBooleanOption(MarketplaceClientCore.BUNDLE_ID + DEBUG_FAKE_CLIENT_OPTION, + false); + } + DEBUG = debug; + DEBUG_FAKE_CLIENT = fakeClient; + MarketplaceClientCorePlugin.debugTrace = debugTrace; + } + + } } 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 index e8a952c0..ca5716c0 100644 --- 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 @@ -12,7 +12,11 @@ *******************************************************************************/ package org.eclipse.epp.internal.mpc.core; +import java.util.ArrayList; +import java.util.Collection; import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; import org.eclipse.epp.internal.mpc.core.util.TransportFactory; @@ -23,14 +27,25 @@ 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.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentConstants; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; import org.osgi.util.tracker.ServiceTracker; /** * @author Carsten Reckord */ +@Component(name = "org.eclipse.epp.mpc.core.servicehelper", service = { ServiceHelper.class, ServiceHelperImpl.class }) public class ServiceHelperImpl extends ServiceHelper { + private static ServiceHelperImpl instance; + private ServiceTracker<IMarketplaceServiceLocator, IMarketplaceServiceLocator> locatorServiceTracker; private ServiceTracker<ITransportFactory, ITransportFactory> transportFactoryTracker; @@ -39,27 +54,45 @@ public class ServiceHelperImpl extends ServiceHelper { private ServiceTracker<IMarketplaceUnmarshaller, IMarketplaceUnmarshaller> unmarshallerTracker; - private BundleContext context; + private ComponentContext context; + + private List<ServiceRegistration<?>> serviceRegistrations; - void startTracking(final BundleContext context) { + @Activate + void activate(final ComponentContext context) throws InvalidSyntaxException { this.context = context; - locatorServiceTracker = new ServiceTracker<>(context, + BundleContext bundleContext = context.getBundleContext(); + + registerServices(bundleContext); + + locatorServiceTracker = new ServiceTracker<>(bundleContext, IMarketplaceServiceLocator.class, null); locatorServiceTracker.open(true); - transportFactoryTracker = new ServiceTracker<>(context, + transportFactoryTracker = new ServiceTracker<>(bundleContext, ITransportFactory.class, null); transportFactoryTracker.open(true); - legacyTransportFactoryTracker = new TransportFactory.LegacyTransportFactoryTracker(context); + legacyTransportFactoryTracker = new TransportFactory.LegacyTransportFactoryTracker(bundleContext); legacyTransportFactoryTracker.open(true); - unmarshallerTracker = new ServiceTracker<>(context, + unmarshallerTracker = new ServiceTracker<>(bundleContext, IMarketplaceUnmarshaller.class, null); unmarshallerTracker.open(true); + synchronized (ServiceHelperImpl.class) { + if (instance == null) { + instance = this; + } + } } - void stopTracking(BundleContext context) { + @Deactivate + void deactivate(BundleContext context) { + synchronized (ServiceHelperImpl.class) { + if (instance == this) { + instance = null; + } + } this.context = null; if (locatorServiceTracker != null) { locatorServiceTracker.close(); @@ -77,6 +110,65 @@ public class ServiceHelperImpl extends ServiceHelper { unmarshallerTracker.close(); unmarshallerTracker = null; } + unregisterServices(); + } + + private void registerServices(BundleContext context) throws InvalidSyntaxException { + List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<>(); + this.serviceRegistrations = serviceRegistrations; + + List<ITransportFactory> factories = TransportFactory.listAvailableFactories();//highest-prio factory comes first + if (factories.isEmpty()) { + return; + } + + Collection<ServiceReference<ITransportFactory>> serviceReferences = context + .getServiceReferences(ITransportFactory.class, null); + int lowestPriority = Integer.MAX_VALUE; + for (ServiceReference<ITransportFactory> serviceReference : serviceReferences) { + Object legacyProperty = serviceReference.getProperty(TransportFactory.LEGACY_TRANSPORT_KEY); + if (legacyProperty != null) { + continue; + } + Integer ranking = (Integer) serviceReference.getProperty(Constants.SERVICE_RANKING); + lowestPriority = Math.min(lowestPriority, ranking == null ? 0 : ranking.intValue()); + } + + int maxLegacyPriority, step; + if (lowestPriority >= 0) { + maxLegacyPriority = -100; + step = 100; + } else { + int available = lowestPriority - Integer.MIN_VALUE; + step = Math.min(100, available / factories.size()); + if (step == 0) { + step = 1; + maxLegacyPriority = Integer.MIN_VALUE + factories.size(); + } else { + maxLegacyPriority = lowestPriority - step; + } + } + int prio = maxLegacyPriority;//prio counts down from 0 in steps of 100 + for (ITransportFactory factory : factories) { + Hashtable<String, Object> properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, prio); + properties.put(ComponentConstants.COMPONENT_NAME, "legacy:" + factory.getClass().getName()); + properties.put(TransportFactory.LEGACY_TRANSPORT_KEY, true); + ServiceRegistration<ITransportFactory> registration = context.registerService(ITransportFactory.class, + factory, properties); + serviceRegistrations.add(registration); + prio -= step; + } + } + + private void unregisterServices() { + List<ServiceRegistration<?>> serviceRegistrations = this.serviceRegistrations; + this.serviceRegistrations = null; + if (serviceRegistrations != null) { + for (ServiceRegistration<?> serviceRegistration : serviceRegistrations) { + serviceRegistration.unregister(); + } + } } @Override @@ -107,30 +199,60 @@ public class ServiceHelperImpl extends ServiceHelper { public ServiceRegistration<IMarketplaceServiceLocator> registerMarketplaceServiceLocator( IMarketplaceServiceLocator marketplaceServiceLocator) { - return context.registerService(IMarketplaceServiceLocator.class, marketplaceServiceLocator, - ServiceUtil.higherServiceRanking(locatorServiceTracker.getServiceReference(), null)); + return context.getBundleContext() + .registerService(IMarketplaceServiceLocator.class, marketplaceServiceLocator, + ServiceUtil.higherServiceRanking(locatorServiceTracker.getServiceReference(), null)); } public ServiceRegistration<IMarketplaceUnmarshaller> registerMarketplaceUnmarshaller( IMarketplaceUnmarshaller unmarshaller) { - return context.registerService(IMarketplaceUnmarshaller.class, unmarshaller, - ServiceUtil.higherServiceRanking(unmarshallerTracker.getServiceReference(), null)); + return context.getBundleContext() + .registerService(IMarketplaceUnmarshaller.class, unmarshaller, + ServiceUtil.higherServiceRanking(unmarshallerTracker.getServiceReference(), null)); } public ServiceRegistration<ITransportFactory> registerTransportFactory(ITransportFactory transportFactory) { - return context.registerService(ITransportFactory.class, transportFactory, - ServiceUtil.higherServiceRanking(transportFactoryTracker.getServiceReference(), null)); + return context.getBundleContext() + .registerService(ITransportFactory.class, transportFactory, + ServiceUtil.higherServiceRanking(transportFactoryTracker.getServiceReference(), null)); } public ServiceRegistration<IMarketplaceService> registerMarketplaceService(String baseUrl, IMarketplaceService marketplaceService) { Dictionary<String, Object> properties = ServiceUtil.serviceRanking(Integer.MAX_VALUE, null); properties.put(IMarketplaceService.BASE_URL, baseUrl); - return context.registerService(IMarketplaceService.class, marketplaceService, properties); + return context.getBundleContext().registerService(IMarketplaceService.class, marketplaceService, properties); } public ServiceRegistration<ICatalogService> registerCatalogService(ICatalogService catalogService) { - return context.registerService(ICatalogService.class, catalogService, - ServiceUtil.serviceRanking(Integer.MAX_VALUE, null)); + return context.getBundleContext() + .registerService(ICatalogService.class, catalogService, + ServiceUtil.serviceRanking(Integer.MAX_VALUE, null)); + } + + /** + * @noreference For test purposes only. This method is not intended to be referenced by clients. + */ + public void setSuspended(boolean suspend) throws Exception { + String pid = (String) context.getProperties().get(Constants.SERVICE_PID); + if (suspend) { + context.disableComponent(pid); + unregisterServices(); + } else { + context.enableComponent(pid); + //registerServices(context.getBundleContext()); + } + } + + public static ServiceHelperImpl getImplInstance() { + synchronized (ServiceHelperImpl.class) { + if (instance == null) { + ServiceHelperImpl registered = ServiceUtil.getService(ServiceHelperImpl.class, ServiceHelperImpl.class); + if (instance == null && registered != null) { + instance = registered; + } + } + return instance; + } } } 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 1cb1a4da..5347fe38 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 @@ -29,6 +29,7 @@ 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.MarketplaceStorageService; import org.eclipse.epp.internal.mpc.core.service.UserFavoritesService; +import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService; import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; import org.eclipse.epp.internal.mpc.core.util.URLUtil; import org.eclipse.epp.mpc.core.service.ICatalogService; @@ -42,6 +43,10 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; @@ -51,9 +56,10 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; * @author David Green * @author Carsten Reckord */ +@Component(name = "org.eclipse.epp.mpc.core.servicelocator", service = IMarketplaceServiceLocator.class) public class ServiceLocator implements IMarketplaceServiceLocator { - public static final String STORAGE_SERVICE_BINDING_ID = "bind.storageService"; //$NON-NLS-1$ + private static final String STORAGE_SERVICE_BINDING_ID = "bind.storageService"; //$NON-NLS-1$ private abstract class DynamicBindingOperation<T, B> implements ServiceReferenceOperation<T> { @@ -113,11 +119,69 @@ public class ServiceLocator implements IMarketplaceServiceLocator { private final List<ServiceRegistration<?>> dynamicServiceRegistrations = new ArrayList<>(); + private HttpClientService httpClient; + public ServiceLocator() { defaultMarketplaceUrl = DefaultMarketplaceService.DEFAULT_SERVICE_URL; defaultCatalogUrl = DefaultCatalogService.DEFAULT_CATALOG_SERVICE_URL; } + public HttpClientService getHttpClient() { + return httpClient; + } + + public void setHttpClient(HttpClientService httpClient) { + HttpClientService oldClient = this.httpClient; + this.httpClient = httpClient; + if (oldClient != httpClient) { + updateHttpClient(httpClient); + } + } + + @Reference(unbind = "unbindHttpClient", cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC) + public void bindHttpClient(HttpClientService httpClient) { + setHttpClient(httpClient); + } + + public void unbindHttpClient(HttpClientService httpClient) { + if (this.httpClient == httpClient) { + setHttpClient(null); + } + } + + private void updateHttpClient(HttpClientService httpClient) { + applyServiceReferenceOperation(favoritesServiceTracker, new ServiceReferenceOperation<IUserFavoritesService>() { + + @Override + public void apply(ServiceReference<IUserFavoritesService> reference) { + ServiceRegistration<IUserFavoritesService> registration = getDynamicServiceInstance(reference); + if (registration != null) { + IUserFavoritesService service = ServiceUtil.getService(registration); + if (service instanceof UserFavoritesService) { + if (httpClient == null) { + ((UserFavoritesService) service).unbindHttpClient(httpClient); + } else { + ((UserFavoritesService) service).bindHttpClient(httpClient); + } + } + } + } + }); + applyServiceReferenceOperation(marketplaceServiceTracker, new ServiceReferenceOperation<IMarketplaceService>() { + + @Override + public void apply(ServiceReference<IMarketplaceService> reference) { + ServiceRegistration<IMarketplaceService> registration = getDynamicServiceInstance(reference); + if (registration != null) { + IMarketplaceService service = ServiceUtil.getService(registration); + if (service instanceof DefaultMarketplaceService) { + ((DefaultMarketplaceService) service).setHttpClient(httpClient); + } + } + } + }); + } + /** * @deprecated use {@link #getDefaultMarketplaceService()} or {@link #getMarketplaceService(String)} instead */ @@ -194,6 +258,7 @@ public class ServiceLocator implements IMarketplaceServiceLocator { defaultService.setRequestMetaParameters(requestMetaParameters); IUserFavoritesService favoritesService = getFavoritesService(baseUrl); defaultService.setUserFavoritesService(favoritesService);//FIXME this should be a service reference! + defaultService.setHttpClient(httpClient); service = new CachingMarketplaceService(defaultService); return service; } @@ -229,6 +294,7 @@ public class ServiceLocator implements IMarketplaceServiceLocator { } UserFavoritesService favoritesService = new UserFavoritesService(); favoritesService.bindStorageService(storageService); + favoritesService.bindHttpClient(httpClient); registerService(marketplaceBaseUrl, IUserFavoritesService.class, favoritesService); return favoritesService; } 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 083da73d..ab3dcd3c 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 @@ -20,6 +20,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; @@ -32,9 +33,9 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; import org.apache.http.message.BasicNameValuePair; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -52,7 +53,8 @@ import org.eclipse.epp.internal.mpc.core.model.NodeListing; import org.eclipse.epp.internal.mpc.core.model.Search; import org.eclipse.epp.internal.mpc.core.model.SearchResult; import org.eclipse.epp.internal.mpc.core.service.AbstractDataStorageService.NotAuthorizedException; -import org.eclipse.epp.internal.mpc.core.util.HttpUtil; +import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService; +import org.eclipse.epp.internal.mpc.core.transport.httpclient.RequestTemplate; import org.eclipse.epp.internal.mpc.core.util.ServiceUtil; import org.eclipse.epp.internal.mpc.core.util.URLUtil; import org.eclipse.epp.mpc.core.model.ICategory; @@ -118,6 +120,8 @@ MarketplaceService { public static final String API_FREETAGGING_URI = "category/free-tagging/"; //$NON-NLS-1$ + private static final String API_ERROR_REPORT_URI = "install/error/report"; //$NON-NLS-1$ + public static final String DEFAULT_SERVICE_LOCATION = System .getProperty(IMarketplaceServiceLocator.DEFAULT_MARKETPLACE_PROPERTY_NAME, "http://marketplace.eclipse.org"); //$NON-NLS-1$ @@ -171,6 +175,8 @@ MarketplaceService { private IUserFavoritesService userFavoritesService; + private HttpClientService httpClient; + public DefaultMarketplaceService(URL baseUrl) { this.baseUrl = baseUrl == null ? DEFAULT_SERVICE_URL : baseUrl; } @@ -775,19 +781,6 @@ MarketplaceService { @Override public void reportInstallError(IStatus result, Set<? extends INode> nodes, Set<String> iuIdsAndVersions, String resolutionDetails, IProgressMonitor monitor) throws CoreException { - HttpClient client; - URL location; - HttpPost method; - try { - location = new URL(baseUrl, "install/error/report"); //$NON-NLS-1$ - String target = location.toURI().toString(); - client = HttpUtil.createHttpClient(target); - method = new HttpPost(target); - } catch (URISyntaxException e) { - throw new IllegalStateException(e); - } catch (MalformedURLException e) { - throw new IllegalStateException(e); - } try { List<NameValuePair> parameters = new ArrayList<>(); @@ -811,15 +804,29 @@ MarketplaceService { parameters.add(new BasicNameValuePair("detailedMessage", resolutionDetails)); //$NON-NLS-1$ if (!parameters.isEmpty()) { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8); - method.setEntity(entity); - client.execute(method); + new RequestTemplate<Void>() { + + @Override + protected HttpUriRequest createRequest(URI uri) { + return RequestBuilder.post(uri.resolve(API_ERROR_REPORT_URI)).setEntity(entity).build(); + } + + @Override + protected Void handleResponseStream(InputStream content, Charset charset) throws IOException { + // ignore + return null; + } + + }.execute(httpClient, baseUrl.toURI()); } + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); } catch (IOException e) { String message = NLS.bind(Messages.DefaultMarketplaceService_cannotCompleteRequest_reason, - location.toString(), e.getMessage()); + baseUrl.toString() + API_ERROR_REPORT_URI, e.getMessage()); throw new CoreException(createErrorStatus(message, e)); - } finally { - client.getConnectionManager().shutdown(); } } @@ -854,4 +861,12 @@ MarketplaceService { public void setUserFavoritesService(IUserFavoritesService userFavoritesService) { this.userFavoritesService = userFavoritesService; } + + public void setHttpClient(HttpClientService httpClient) { + this.httpClient = httpClient; + } + + public HttpClientService getHttpClient() { + return httpClient; + } } 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 index 0abcaf52..37f4d8a2 100644 --- 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 @@ -37,6 +37,7 @@ 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.osgi.service.component.annotations.Component; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -44,6 +45,7 @@ import org.xml.sax.XMLReader; /** * @author Carsten Reckord */ +@Component(name = "org.eclipse.epp.mpc.core.unmarshaller") public class MarketplaceUnmarshaller implements IMarketplaceUnmarshaller { @Override diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/UserFavoritesService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/UserFavoritesService.java index 5bc2b506..b05ac7da 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/UserFavoritesService.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/service/UserFavoritesService.java @@ -37,7 +37,8 @@ import java.util.regex.Pattern; import org.apache.http.HttpHeaders; import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -45,6 +46,7 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.model.FavoriteList; +import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService; import org.eclipse.epp.internal.mpc.core.transport.httpclient.RequestTemplate; import org.eclipse.epp.internal.mpc.core.util.URLUtil; import org.eclipse.epp.mpc.core.model.IFavoriteList; @@ -138,6 +140,8 @@ public class UserFavoritesService extends AbstractDataStorageService implements private final Set<String> favorites = new HashSet<>(); + private HttpClientService httpClient; + protected IBlob getFavoritesBlob() { return getStorageService().getBlob(KEY); } @@ -232,7 +236,7 @@ public class UserFavoritesService extends AbstractDataStorageService implements return favoritesByUserId; } - }.execute(randomFavoritesUri); + }.execute(httpClient, randomFavoritesUri); } private static String getAttribute(Pattern attributePattern, String attributeName, String entryBody) { @@ -518,7 +522,7 @@ public class UserFavoritesService extends AbstractDataStorageService implements return null; } - }.execute(uri); + }.execute(httpClient, uri); } catch (FileNotFoundException e) { return new ArrayList<>(); } @@ -617,10 +621,10 @@ public class UserFavoritesService extends AbstractDataStorageService implements } @Override - protected Request configureRequest(Request request, URI uri) { - return super.configureRequest(request, uri).setHeader(HttpHeaders.USER_AGENT, Session.USER_AGENT_ID) - .addHeader(HttpHeaders.CONTENT_TYPE, Session.APPLICATION_JSON) // - .addHeader(HttpHeaders.ACCEPT, Session.APPLICATION_JSON); + protected HttpUriRequest configureRequest(HttpClientService client, HttpUriRequest request) { + HttpUriRequest configuredRequest = super.configureRequest(client, request); + configuredRequest.setHeader(HttpHeaders.USER_AGENT, Session.USER_AGENT_ID); + return configuredRequest; } @Override @@ -675,8 +679,30 @@ public class UserFavoritesService extends AbstractDataStorageService implements protected abstract T parseListElement(String listElement); @Override - protected Request createRequest(URI uri) { - return Request.Get(uri); + protected HttpUriRequest createRequest(URI uri) { + return RequestBuilder.get(uri) + .addHeader(HttpHeaders.CONTENT_TYPE, Session.APPLICATION_JSON) // + .addHeader(HttpHeaders.ACCEPT, Session.APPLICATION_JSON) + .build(); } } + + public void setHttpClient(HttpClientService httpClient) { + this.httpClient = httpClient; + } + + public HttpClientService getHttpClient() { + return httpClient; + } + + public void bindHttpClient(HttpClientService httpClient) { + setHttpClient(httpClient); + } + + public void unbindHttpClient(HttpClientService httpClient) { + if (this.httpClient == httpClient) { + setHttpClient(null); + } + } + } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientFactory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientFactory.java index d8728626..d779f174 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientFactory.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientFactory.java @@ -1,231 +1,230 @@ -/******************************************************************************* +/*******************************************************************************
* Copyright (c) 2010, 2018 The Eclipse Foundation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at + * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * The Eclipse Foundation - initial API and implementation - *******************************************************************************/ -package org.eclipse.epp.internal.mpc.core.transport.httpclient; - -import java.util.Collection; -import java.util.Collections; - -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.client.CookieStore; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.fluent.Executor; -import org.apache.http.config.SocketConfig; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; -import org.apache.http.impl.client.TargetAuthenticationStrategy; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; -import org.eclipse.userstorage.internal.StorageProperties; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; - -class HttpClientFactory { - - private CredentialsProvider credentialsProvider; - - private CookieStore cookieStore; - - private HttpClient client; - - private Executor executor; - - public HttpClient build() { - HttpClientBuilder clientBuilder = createClientBuilder(); - - if (cookieStore == null) { - cookieStore = new BasicCookieStore(); - } - - if (credentialsProvider == null) { - credentialsProvider = createCredentialsProvider(clientBuilder); - } - - clientBuilder.setDefaultCredentialsProvider(credentialsProvider); - clientBuilder.setDefaultCookieStore(cookieStore); - client = clientBuilder.build(); - - executor = Executor.newInstance(client).use(cookieStore).use(credentialsProvider); - - return client; - } - - private static CredentialsProvider createCredentialsProvider(HttpClientBuilder clientBuilder) { - //TODO we should handle configured proxy passwords and dialogs to prompt for unknown credentials on our own... - CredentialsProvider credentialsProvider = new SystemCredentialsProvider(); - credentialsProvider = customizeCredentialsProvider(credentialsProvider); - - final CacheCredentialsProvider cacheProvider = new CacheCredentialsProvider(); - credentialsProvider = new ChainedCredentialsProvider(cacheProvider, credentialsProvider); - credentialsProvider = new SynchronizedCredentialsProvider(credentialsProvider); - - clientBuilder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> context - .setAttribute(CacheCredentialsAuthenticationStrategy.CREDENTIALS_CACHE_ATTRIBUTE, cacheProvider)); - - return credentialsProvider; - } - - private static HttpClientBuilder createClientBuilder() { - HttpClientBuilder builder = HttpClientBuilder.create(); - builder = customizeBuilder(builder); - - builder.setMaxConnPerRoute(100).setMaxConnTotal(200); - setClientTimeouts(builder); - - builder.setTargetAuthenticationStrategy( - new CacheCredentialsAuthenticationStrategy.Target(TargetAuthenticationStrategy.INSTANCE)); - builder.setProxyAuthenticationStrategy( - new CacheCredentialsAuthenticationStrategy.Proxy(ProxyAuthenticationStrategy.INSTANCE)); - - builder.setUserAgent(HttpClientTransport.USER_AGENT); - - return builder; - } - - private static void setClientTimeouts(HttpClientBuilder builder) { - @SuppressWarnings("restriction") - int connectTimeoutUssDefault = StorageProperties - .getProperty(StorageProperties.CONNECT_TIMEOUT, HttpClientTransport.DEFAULT_CONNECT_TIMEOUT); - @SuppressWarnings("restriction") - int readTimeoutUssDefault = StorageProperties.getProperty(StorageProperties.SOCKET_TIMEOUT, - HttpClientTransport.DEFAULT_READ_TIMEOUT); - - int connectTimeout = getTimeoutValue(HttpClientTransport.CONNECT_TIMEOUT_PROPERTY, connectTimeoutUssDefault); - int readTimeout = getTimeoutValue(HttpClientTransport.READ_TIMEOUT_PROPERTY, readTimeoutUssDefault); - - int connectionRequestTimeout = getTimeoutValue(HttpClientTransport.CONNECTION_REQUEST_TIMEOUT_PROPERTY, - HttpClientTransport.DEFAULT_CONNECTION_REQUEST_TIMEOUT); - - SocketConfig defaultSocketConfig = SocketConfig.copy(SocketConfig.DEFAULT) - .setSoTimeout(readTimeout) - .setTcpNoDelay(true)//Disable Nagle - see https://en.wikipedia.org/wiki/Nagle%27s_algorithm#Negative_effect_on_larger_writes - //.setSoLinger(0) - //TODO is it safe to set this to 0? This will forcefully terminate sockets on close instead of waiting for graceful close - //See http://docs.oracle.com/javase/6/docs/api/java/net/SocketOptions.html?is-external=true#SO_LINGER - //and https://issues.apache.org/jira/browse/HTTPCLIENT-1497 - .build(); - RequestConfig defaultRequestConfig = RequestConfig.copy(RequestConfig.DEFAULT) - .setSocketTimeout(readTimeout) - .setConnectTimeout(connectTimeout) - .setConnectionRequestTimeout(connectionRequestTimeout) - .build(); - builder.setDefaultSocketConfig(defaultSocketConfig); - builder.setDefaultRequestConfig(defaultRequestConfig); - } - - private static int getTimeoutValue(String property, int defaultValue) { - String propertyValue = FrameworkUtil.getBundle(HttpClientTransport.class) - .getBundleContext() - .getProperty(property); - if (propertyValue == null || "".equals(propertyValue)) { //$NON-NLS-1$ - return defaultValue; - } - try { - return Integer.parseInt(propertyValue); - } catch (NumberFormatException ex) { - //TODO log - return defaultValue; - } - } - - private static HttpClientBuilder customizeBuilder(HttpClientBuilder builder) { - BundleContext context = getBundleContext(); - Collection<ServiceReference<HttpClientCustomizer>> serviceReferences = getClientBuilderCustomizers(context); - HttpClientBuilder customBuilder = builder; - for (ServiceReference<HttpClientCustomizer> reference : serviceReferences) { - try { - HttpClientCustomizer service = context.getService(reference); - customBuilder = customizeBuilder(service, customBuilder); - } finally { - context.ungetService(reference); - } - } - return customBuilder; - } - - private static HttpClientBuilder customizeBuilder(HttpClientCustomizer service, HttpClientBuilder builder) { - if (service == null) { - return builder; - } - HttpClientBuilder customBuilder = service.customizeBuilder(builder); - return customBuilder == null ? builder : customBuilder; - } - - private static CredentialsProvider customizeCredentialsProvider(CredentialsProvider credentialsProvider) { - BundleContext context = getBundleContext(); - Collection<ServiceReference<HttpClientCustomizer>> serviceReferences = getClientBuilderCustomizers(context); - CredentialsProvider customizedCredentialsProvider = credentialsProvider; - for (ServiceReference<HttpClientCustomizer> reference : serviceReferences) { - try { - HttpClientCustomizer service = context.getService(reference); - customizedCredentialsProvider = customizeCredentialsProvider(service, customizedCredentialsProvider); - } finally { - context.ungetService(reference); - } - } - return customizedCredentialsProvider; - } - - private static CredentialsProvider customizeCredentialsProvider(HttpClientCustomizer service, - CredentialsProvider credentialsProvider) { - if (service == null) { - return credentialsProvider; - } - CredentialsProvider customCredentialsProvider = service.customizeCredentialsProvider(credentialsProvider); - return customCredentialsProvider == null ? credentialsProvider : customCredentialsProvider; - } - - private static BundleContext getBundleContext() { - return FrameworkUtil.getBundle(HttpClientTransport.class).getBundleContext(); - } - - private static Collection<ServiceReference<HttpClientCustomizer>> getClientBuilderCustomizers( - BundleContext context) { - Collection<ServiceReference<HttpClientCustomizer>> serviceReferences; - try { - serviceReferences = context.getServiceReferences(HttpClientCustomizer.class, - /*TransportFactory.computeDisabledTransportsFilter()*/null); - } catch (InvalidSyntaxException e) { - MarketplaceClientCore.error(e); - serviceReferences = Collections.emptySet(); - } - return serviceReferences; - } - - public void setCredentialsProvider(CredentialsProvider credentialsProvider) { - this.credentialsProvider = credentialsProvider; - } - - public CredentialsProvider getCredentialsProvider() { - return credentialsProvider; - } - - public void setCookieStore(CookieStore cookieStore) { - this.cookieStore = cookieStore; - } - - public CookieStore getCookieStore() { - return cookieStore; - } - - public Executor getExecutor() { - return executor; - } - - public HttpClient getClient() { - return client; - } -} + *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.core.transport.httpclient;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.ProxyAuthenticationStrategy;
+import org.apache.http.impl.client.TargetAuthenticationStrategy;
+import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
+import org.eclipse.userstorage.internal.StorageProperties;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.FieldOption;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+@Component(name = "org.eclipse.epp.mpc.core.http.client.factory", service = { HttpClientFactory.class })
+public class HttpClientFactory { +
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.STATIC, fieldOption = FieldOption.REPLACE)
+ private List<HttpClientCustomizer> customizers;
+
+ public List<HttpClientCustomizer> getCustomizers() {
+ return customizers;
+ }
+
+ public void setCustomizers(List<HttpClientCustomizer> customizers) {
+ this.customizers = customizers;
+ }
+
+ public HttpServiceContext build() {
+ return build(null);
+ }
+
+ public HttpServiceContext build(HttpServiceContext oldContext) {
+ HttpClientBuilder clientBuilder = builder();
+
+ CookieStore cookieStore = oldContext == null ? null : oldContext.getCookieStore();
+ if (cookieStore == null) {
+ cookieStore = createCookieStore();
+ }
+
+ CredentialsProvider cacheProvider = oldContext == null ? null
+ : oldContext.getCredentialsCacheProvider();
+ if (cacheProvider == null) {
+ cacheProvider = createCredentialsCacheProvider();
+ }
+ CredentialsProvider initialCredentialsProvider = oldContext == null ? null
+ : oldContext.getInitialCredentialsProvider();
+ if (initialCredentialsProvider == null) {
+ initialCredentialsProvider = createCredentialsProvider();
+ }
+ CredentialsProvider credentialsProvider = initialCredentialsProvider;
+ if (credentialsProvider != null) {
+ credentialsProvider = customizeCredentialsProvider(clientBuilder, credentialsProvider, cacheProvider);
+ }
+
+ clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
+ clientBuilder.setDefaultCookieStore(cookieStore);
+
+ clientBuilder = customizeBuilder(clientBuilder);
+
+ return new HttpServiceContext(clientBuilder.build(), cookieStore, credentialsProvider,
+ initialCredentialsProvider, cacheProvider);
+ }
+
+ protected CredentialsProvider createCredentialsProvider() {
+ return new SystemCredentialsProvider();
+ }
+
+ protected CredentialsProvider createCredentialsCacheProvider() {
+ return new CacheCredentialsProvider();
+ }
+
+ protected CookieStore createCookieStore() {
+ return new BasicCookieStore();
+ }
+
+ private CredentialsProvider customizeCredentialsProvider(HttpClientBuilder clientBuilder,
+ CredentialsProvider credentialsProvider, CredentialsProvider cacheProvider) {
+ //TODO we should handle configured proxy passwords and dialogs to prompt for unknown credentials on our own...
+ credentialsProvider = customizeCredentialsProvider(credentialsProvider);
+
+ if (cacheProvider != null) {
+ credentialsProvider = new ChainedCredentialsProvider(cacheProvider, credentialsProvider);
+
+ clientBuilder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> context
+ .setAttribute(CacheCredentialsAuthenticationStrategy.CREDENTIALS_CACHE_ATTRIBUTE, cacheProvider));
+ }
+ credentialsProvider = new SynchronizedCredentialsProvider(credentialsProvider);
+
+ return credentialsProvider;
+ }
+
+ protected HttpClientBuilder builder() {
+ HttpClientBuilder builder = HttpClientBuilder.create();
+
+ builder.setMaxConnPerRoute(100).setMaxConnTotal(200);
+ setClientDefaultTimeouts(builder);
+
+ builder.setTargetAuthenticationStrategy(
+ new CacheCredentialsAuthenticationStrategy.Target(TargetAuthenticationStrategy.INSTANCE));
+ builder.setProxyAuthenticationStrategy(
+ new CacheCredentialsAuthenticationStrategy.Proxy(ProxyAuthenticationStrategy.INSTANCE));
+
+ builder.setUserAgent(HttpClientTransport.USER_AGENT);
+
+ return builder;
+ }
+
+ private static void setClientDefaultTimeouts(HttpClientBuilder builder) {
+ @SuppressWarnings("restriction")
+ int connectTimeoutUssDefault = StorageProperties.getProperty(StorageProperties.CONNECT_TIMEOUT,
+ HttpClientTransport.DEFAULT_CONNECT_TIMEOUT);
+ @SuppressWarnings("restriction")
+ int readTimeoutUssDefault = StorageProperties.getProperty(StorageProperties.SOCKET_TIMEOUT,
+ HttpClientTransport.DEFAULT_READ_TIMEOUT);
+
+ int connectTimeout = getTimeoutValue(HttpClientTransport.CONNECT_TIMEOUT_PROPERTY, connectTimeoutUssDefault);
+ int readTimeout = getTimeoutValue(HttpClientTransport.READ_TIMEOUT_PROPERTY, readTimeoutUssDefault);
+
+ int connectionRequestTimeout = getTimeoutValue(HttpClientTransport.CONNECTION_REQUEST_TIMEOUT_PROPERTY,
+ HttpClientTransport.DEFAULT_CONNECTION_REQUEST_TIMEOUT);
+
+ SocketConfig defaultSocketConfig = SocketConfig.copy(SocketConfig.DEFAULT)
+ .setSoTimeout(readTimeout)
+ .setTcpNoDelay(true)//Disable Nagle - see https://en.wikipedia.org/wiki/Nagle%27s_algorithm#Negative_effect_on_larger_writes
+ //.setSoLinger(0)
+ //TODO is it safe to set this to 0? This will forcefully terminate sockets on close instead of waiting for graceful close
+ //See http://docs.oracle.com/javase/6/docs/api/java/net/SocketOptions.html?is-external=true#SO_LINGER
+ //and https://issues.apache.org/jira/browse/HTTPCLIENT-1497
+ .build();
+ RequestConfig defaultRequestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
+ .setSocketTimeout(readTimeout)
+ .setConnectTimeout(connectTimeout)
+ .setConnectionRequestTimeout(connectionRequestTimeout)
+ .build();
+ builder.setDefaultSocketConfig(defaultSocketConfig);
+ builder.setDefaultRequestConfig(defaultRequestConfig);
+ }
+
+ private static int getTimeoutValue(String property, int defaultValue) {
+ String propertyValue = FrameworkUtil.getBundle(HttpClientTransport.class)
+ .getBundleContext()
+ .getProperty(property);
+ if (propertyValue == null || "".equals(propertyValue)) { //$NON-NLS-1$
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(propertyValue);
+ } catch (NumberFormatException ex) {
+ //TODO log
+ return defaultValue;
+ }
+ }
+
+ protected HttpClientBuilder customizeBuilder(HttpClientBuilder builder) {
+ HttpClientBuilder customBuilder = builder;
+ for (HttpClientCustomizer customizer : this.customizers) {
+ customBuilder = customizeBuilder(customizer, customBuilder);
+ }
+ return customBuilder;
+ }
+
+ private static HttpClientBuilder customizeBuilder(HttpClientCustomizer customizer, HttpClientBuilder builder) {
+ if (customizer == null) {
+ return builder;
+ }
+ HttpClientBuilder customBuilder = customizer.customizeBuilder(builder);
+ return customBuilder == null ? builder : customBuilder;
+ }
+
+ private CredentialsProvider customizeCredentialsProvider(CredentialsProvider credentialsProvider) {
+ CredentialsProvider customizedCredentialsProvider = credentialsProvider;
+ for (HttpClientCustomizer customizer : this.customizers) {
+ customizedCredentialsProvider = customizeCredentialsProvider(customizer, customizedCredentialsProvider);
+ }
+ return customizedCredentialsProvider;
+ }
+
+ private static CredentialsProvider customizeCredentialsProvider(HttpClientCustomizer customizer,
+ CredentialsProvider credentialsProvider) {
+ if (customizer == null) {
+ return credentialsProvider;
+ }
+ CredentialsProvider customCredentialsProvider = customizer.customizeCredentialsProvider(credentialsProvider);
+ return customCredentialsProvider == null ? credentialsProvider : customCredentialsProvider;
+ }
+
+ private static BundleContext getBundleContext() {
+ return FrameworkUtil.getBundle(HttpClientTransport.class).getBundleContext();
+ }
+
+ private static Collection<ServiceReference<HttpClientCustomizer>> getClientBuilderCustomizers(
+ BundleContext context) {
+ Collection<ServiceReference<HttpClientCustomizer>> serviceReferences;
+ try {
+ serviceReferences = context.getServiceReferences(HttpClientCustomizer.class,
+ /*TransportFactory.computeDisabledTransportsFilter()*/null);
+ } catch (InvalidSyntaxException e) {
+ MarketplaceClientCore.error(e);
+ serviceReferences = Collections.emptySet();
+ }
+ return serviceReferences;
+ }
+}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientService.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientService.java new file mode 100644 index 00000000..46af4d40 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientService.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2010, 2018 The Eclipse Foundation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * The Eclipse Foundation - initial API and implementation + *******************************************************************************/ +package org.eclipse.epp.internal.mpc.core.transport.httpclient; + +import java.io.IOException; +import java.net.URI; + +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.Configurable; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.protocol.HttpContext; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.epp.internal.mpc.core.util.ProxyHelper; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +@Component(name = "org.eclipse.epp.mpc.core.http.client", service = { HttpClientService.class }) +public class HttpClientService { + + private HttpClient client; + + private HttpServiceContext context; + + private IProxyService proxyService; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, updated = "bindClientFactory", unbind = "unbindClientFactory") + void bindClientFactory(HttpClientFactory factory) { + context = factory.build(context); + client = context.getClient(); + } + + void unbindClientFactory(HttpClientFactory factory) { + //do nothing + } + + @Reference(field = "proxyService", unbind = "unbindProxyService", policy = ReferencePolicy.DYNAMIC) + void bindProxyService(IProxyService proxyService) { + this.proxyService = proxyService; + } + + void unbindProxyService(IProxyService proxyService) { + if (this.proxyService == proxyService) { + this.proxyService = null; + } + } + + public HttpResponse execute(HttpUriRequest request) throws ClientProtocolException, IOException { + return execute(request, null); + } + + public HttpResponse execute(HttpUriRequest request, HttpContext context) + throws ClientProtocolException, IOException { + HttpClientContext internalContext = context == null ? new HttpClientContext() + : HttpClientContext.adapt(context); + HttpUriRequest configuredRequest = configureRequestExecution(request, internalContext); + return client.execute(configuredRequest, internalContext); + } + + private HttpUriRequest configureRequestExecution(HttpUriRequest request, HttpClientContext context) + throws IOException { + final RequestConfig.Builder builder; + RequestConfig requestConfig = context.getRequestConfig(); + + if (requestConfig != null) { + builder = RequestConfig.copy(requestConfig); + } else if (request instanceof Configurable && ((Configurable) request).getConfig() != null) { + builder = RequestConfig.copy(((Configurable) request).getConfig()); + } else if (client instanceof Configurable && ((Configurable) client).getConfig() != null) { + builder = RequestConfig.copy(((Configurable) client).getConfig()); + } else { + builder = RequestConfig.custom(); + } + + configureRequestExecution(request, context, builder); + + RequestConfig config = builder.build(); + if (request instanceof HttpRequestBase) { + ((HttpRequestBase) request).setConfig(config); + return request; + } else { + return RequestBuilder.copy(request).setConfig(config).build(); + } + } + + protected void configureRequestExecution(HttpUriRequest request, HttpClientContext context, + RequestConfig.Builder builder) throws IOException { + configureProxy(request.getURI(), context, builder); + } + + private static HttpUriRequest setConfig(HttpUriRequest request, RequestConfig config) { + if (request instanceof HttpRequestBase) { + ((HttpRequestBase) request).setConfig(config); + } else { + request = RequestBuilder.copy(request).setConfig(config).build(); + } + return request; + } + + public HttpUriRequest configureRequest(HttpUriRequest request) { + if (client instanceof Configurable && ((Configurable) client).getConfig() != null) { + return setConfig(request, ((Configurable) client).getConfig()); + } + return request; + } + + public HttpResponse configureAndExecute(HttpUriRequest request) throws ClientProtocolException, IOException { + return configureAndExecute(request, null); + } + + public HttpResponse configureAndExecute(HttpUriRequest request, HttpContext context) + throws ClientProtocolException, IOException { + return execute(configureRequest(request), context); + } + + public HttpClient getClient() { + return client; + } + + public IProxyService getProxyService() { + return proxyService; + } + + private IProxyData getProxyData(URI uri) { + return proxyService == null ? null : ProxyHelper.getProxyData(uri, proxyService); + } + + private HttpHost getProxyHost(IProxyData proxy) { + if (IProxyData.HTTPS_PROXY_TYPE.equals(proxy.getType()) || IProxyData.HTTP_PROXY_TYPE.equals(proxy.getType())) { + return new HttpHost(proxy.getHost(), proxy.getPort()); + } + //SOCKS proxies are handled by Java on the socket level + return null; + } + + private void configureProxy(URI uri, HttpClientContext context, RequestConfig.Builder builder) throws IOException { + IProxyData proxy = getProxyData(uri); + if (proxy != null) { + builder.setProxy(getProxyHost(proxy)); + setProxyAuthentication(context, proxy); + } else { + builder.setProxy(null); + } + } + + private void setProxyAuthentication(HttpClientContext context, IProxyData proxy) throws IOException { + String proxyUserID; + HttpHost proxyHost; + if ((proxyUserID = proxy.getUserId()) != null && (proxyHost = getProxyHost(proxy)) != null) { + String domainUserID = NTLMDomainUtil.getNTLMUserName(proxyUserID); + String password = proxy.getPassword(); + String domain = NTLMDomainUtil.getNTLMUserDomain(proxyUserID); + if (domain != null || !proxyUserID.equals(domainUserID)) { + String workstation = NTLMDomainUtil.getNTLMWorkstation(); + setAuth(context, new AuthScope(proxyHost, AuthScope.ANY_REALM, "ntlm"), //$NON-NLS-1$ + new NTCredentials(domainUserID, password, workstation, domain)); + } else { + setAuth(context, new AuthScope(proxyHost, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME), + new UsernamePasswordCredentials(proxyUserID, password)); + } + } + } + + private void setAuth(HttpClientContext clientContext, AuthScope authScope, Credentials credentials) { + CredentialsProvider authStore = clientContext.getCredentialsProvider(); + if (authStore == null) { + authStore = new BasicCredentialsProvider(); + authStore = new ChainedCredentialsProvider(authStore, this.context.getCredentialsProvider()); + clientContext.setCredentialsProvider(authStore); + } + authStore.setCredentials(authScope, credentials); + } +} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransport.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransport.java index 103bcdbb..ec175a2d 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransport.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransport.java @@ -21,14 +21,14 @@ import java.nio.charset.Charset; import java.util.concurrent.TimeUnit; import org.apache.http.HttpEntity; +import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpResponseException; -import org.apache.http.client.fluent.Executor; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.fluent.Response; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -37,7 +37,11 @@ import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.util.UserAgentUtil; import org.eclipse.epp.mpc.core.service.ITransport; import org.eclipse.epp.mpc.core.service.ServiceUnavailableException; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +@Component(name = "org.eclipse.epp.mpc.core.transport.http", service = { HttpClientTransport.class, + ITransport.class }) public class HttpClientTransport implements ITransport { public static final String USER_AGENT; @@ -72,36 +76,30 @@ public class HttpClientTransport implements ITransport { USER_AGENT = UserAgentUtil.computeUserAgent(); } - private final HttpClient client; - - private final Executor executor; - - public HttpClientTransport() { - HttpClientFactory httpClientFactory = new HttpClientFactory(); - client = httpClientFactory.build(); - executor = httpClientFactory.getExecutor(); - } + private HttpClientService clientService; public HttpClient getClient() { - return client; + return clientService.getClient(); } - public Executor getExecutor() { - return executor; + @Reference + public void bindHttpClientService(HttpClientService service) { + this.clientService = service; } - protected Response execute(Request request, URI uri) throws ClientProtocolException, IOException { - return HttpClientProxyUtil.proxyAuthentication(executor, uri).execute(request); + + protected HttpResponse execute(HttpUriRequest request) throws ClientProtocolException, IOException { + return clientService.execute(request); } - protected Request configureRequest(Request request, URI uri) { - return request.viaProxy(HttpClientProxyUtil.getProxyHost(uri)); + protected HttpRequest configureRequest(HttpUriRequest request) { + return clientService.configureRequest(request); } @Override public InputStream stream(URI location, IProgressMonitor monitor) throws FileNotFoundException, ServiceUnavailableException, CoreException { try { - return createStreamingRequest().execute(location); + return createStreamingRequest().execute(clientService, location); } catch (HttpResponseException e) { int statusCode = e.getStatusCode(); switch (statusCode) { @@ -121,18 +119,17 @@ public class HttpClientTransport implements ITransport { } protected RequestTemplate<InputStream> createStreamingRequest() { - return new RequestTemplate<InputStream>(this) { + return new RequestTemplate<InputStream>() { @Override - protected Request createRequest(URI uri) { - return Request.Get(uri); + protected HttpUriRequest createRequest(URI uri) { + return new HttpGet(uri); } @Override - protected InputStream handleResponse(Response response) throws ClientProtocolException, IOException { - HttpResponse returnResponse = response.returnResponse(); - HttpEntity entity = returnResponse.getEntity(); - StatusLine statusLine = returnResponse.getStatusLine(); + protected InputStream handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + HttpEntity entity = response.getEntity(); + StatusLine statusLine = response.getStatusLine(); handleResponseStatus(statusLine.getStatusCode(), statusLine.getReasonPhrase()); return handleResponseEntity(entity); } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransportFactory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransportFactory.java index 2a332012..ff6c5df6 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransportFactory.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientTransportFactory.java @@ -14,7 +14,13 @@ package org.eclipse.epp.internal.mpc.core.transport.httpclient; import org.eclipse.epp.mpc.core.service.ITransport; import org.eclipse.epp.mpc.core.service.ITransportFactory; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +@Component(name = "org.eclipse.epp.mpc.core.transport.http.factory", service = { HttpClientTransportFactory.class, + ITransportFactory.class }) public class HttpClientTransportFactory implements ITransportFactory { private HttpClientTransport transport; @@ -28,6 +34,7 @@ public class HttpClientTransportFactory implements ITransportFactory { this.transport = transport; } + @Reference(name = "org.eclipse.epp.mpc.core.transport.http", unbind = "unbindTransport", cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC) public void bindTransport(HttpClientTransport transport) { setTransport(transport); } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpServiceContext.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpServiceContext.java new file mode 100644 index 00000000..5b16c348 --- /dev/null +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpServiceContext.java @@ -0,0 +1,59 @@ +/*******************************************************************************
+ * Copyright (c) 2018 The Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * The Eclipse Foundation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.epp.internal.mpc.core.transport.httpclient;
+
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+public class HttpServiceContext {
+
+ private final CloseableHttpClient client;
+
+ private final CookieStore cookieStore;
+
+ private final CredentialsProvider credentialsProvider;
+
+ private final CredentialsProvider credentialsCacheProvider;
+
+ private final CredentialsProvider initialCredentialsProvider;
+
+ HttpServiceContext(CloseableHttpClient client, CookieStore cookieStore, CredentialsProvider credentialsProvider,
+ CredentialsProvider initialCredentialsProvider, CredentialsProvider credentialsCacheProvider) {
+ this.client = client;
+ this.cookieStore = cookieStore;
+ this.credentialsProvider = credentialsProvider;
+ this.initialCredentialsProvider = initialCredentialsProvider;
+ this.credentialsCacheProvider = credentialsCacheProvider;
+ }
+
+ public CloseableHttpClient getClient() {
+ return client;
+ }
+
+ public CookieStore getCookieStore() {
+ return cookieStore;
+ }
+
+ public CredentialsProvider getCredentialsProvider() {
+ return credentialsProvider;
+ }
+
+ CredentialsProvider getInitialCredentialsProvider() {
+ return initialCredentialsProvider;
+ }
+
+ CredentialsProvider getCredentialsCacheProvider() {
+ return credentialsCacheProvider;
+ }
+}
diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientProxyUtil.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/NTLMDomainUtil.java index 44fc9851..33f7e1ab 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/HttpClientProxyUtil.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/NTLMDomainUtil.java @@ -12,20 +12,10 @@ */ package org.eclipse.epp.internal.mpc.core.transport.httpclient; -import java.io.IOException; import java.net.InetAddress; -import java.net.URI; import java.net.UnknownHostException; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.NTCredentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.fluent.Executor; -import org.eclipse.core.net.proxy.IProxyData; -import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.core.runtime.Platform; -import org.eclipse.epp.internal.mpc.core.util.ProxyHelper; /** * This code is based on {@link org.eclipse.userstorage.internal.util.ProxyUtil} and has been copied here to avoid @@ -35,7 +25,7 @@ import org.eclipse.epp.internal.mpc.core.util.ProxyHelper; * @author Carsten Reckord */ @SuppressWarnings("restriction") -final class HttpClientProxyUtil { +final class NTLMDomainUtil { private static final String PROP_HTTP_AUTH_NTLM_DOMAIN = "http.auth.ntlm.domain"; private static final String ENV_USER_DOMAIN = "USERDOMAIN"; @@ -46,44 +36,7 @@ final class HttpClientProxyUtil { private static String workstation; - private HttpClientProxyUtil() { - } - - public static HttpHost getProxyHost(URI uri) { - IProxyData proxy = ProxyHelper.getProxyData(uri); - if (proxy != null) { - if (IProxyData.HTTPS_PROXY_TYPE.equals(proxy.getType()) - || IProxyData.HTTP_PROXY_TYPE.equals(proxy.getType())) { - return new HttpHost(proxy.getHost(), proxy.getPort(), proxy.getType()); - } - //SOCKS proxies are handled by Java on the socket level - return null; - } - - return null; - } - - public static Executor proxyAuthentication(Executor executor, URI uri) - throws IOException { - IProxyData proxy = ProxyHelper.getProxyData(uri); - if (proxy != null) { - HttpHost proxyHost = new HttpHost(proxy.getHost(), proxy.getPort()); - String proxyUserID = proxy.getUserId(); - if (proxyUserID != null) { - String domainUserID = getNTLMUserName(proxyUserID); - String password = proxy.getPassword(); - String domain = getNTLMUserDomain(proxyUserID); - if (domain != null || !proxyUserID.equals(domainUserID)) { - String workstation = getNTLMWorkstation(); - executor.auth(new AuthScope(proxyHost, AuthScope.ANY_REALM, "ntlm"), - new NTCredentials(domainUserID, password, workstation, domain)); - } - return executor.auth(new AuthScope(proxyHost, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME), - new UsernamePasswordCredentials(proxyUserID, password)); - } - } - - return executor; + private NTLMDomainUtil() { } public static String getNTLMWorkstation() { @@ -165,15 +118,4 @@ final class HttpClientProxyUtil { return userName; } - - private static IProxyData getProxyData(IProxyService proxyService, URI uri) { - if (proxyService != null) { - IProxyData[] proxies = proxyService.select(uri); - if (proxies.length != 0) { - return proxies[0]; - } - } - - return null; - } } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/RequestTemplate.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/RequestTemplate.java index e8dcbfea..607f134f 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/RequestTemplate.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/RequestTemplate.java @@ -24,98 +24,41 @@ import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpResponseException; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.fluent.Response; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ContentType; import org.apache.http.util.EntityUtils; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceReference; public abstract class RequestTemplate<T> { - private HttpClientTransport transport; - - private ServiceReference<HttpClientTransport> transportReference; - - public RequestTemplate() { - } - - protected RequestTemplate(HttpClientTransport transport) { - this.transport = transport; - } public String getUserAgent() { return HttpClientTransport.USER_AGENT; } - public T execute(URI uri) throws ClientProtocolException, IOException { - if (transport != null) { - return executeImpl(uri); - } - try { - acquireTransport(); - return executeImpl(uri); - } finally { - releaseTransport(); - } - } - - private void releaseTransport() { - ServiceReference<?> reference = transportReference; - if (reference != null) { - transport = null; - transportReference = null; - Bundle bundle = reference.getBundle(); - if (bundle != null) { - bundle.getBundleContext().ungetService(reference); - } - } - } - - private void acquireTransport() { - Bundle bundle = FrameworkUtil.getBundle(getClass()); - BundleContext bundleContext = bundle.getBundleContext(); - ServiceReference<HttpClientTransport> serviceReference = bundleContext - .getServiceReference(HttpClientTransport.class); - if (serviceReference == null) { - throw new IllegalStateException(); - } - HttpClientTransport transport = bundleContext.getService(serviceReference); - if (transport == null) { - throw new IllegalStateException(); - } - this.transportReference = serviceReference; - this.transport = transport; - } - - protected T executeImpl(URI uri) throws ClientProtocolException, IOException { - Request request = createRequest(uri); - request = configureRequest(request, uri); - Response response = transport.execute(request, uri); + public T execute(HttpClientService client, URI uri) throws ClientProtocolException, IOException { + HttpUriRequest request = createRequest(uri); + request = configureRequest(client, request); + HttpResponse response = client.execute(request); return handleResponse(response); } - protected abstract Request createRequest(URI uri); + protected abstract HttpUriRequest createRequest(URI uri); - protected Request configureRequest(Request request, URI uri) { + protected HttpUriRequest configureRequest(HttpClientService client, HttpUriRequest request) { request.setHeader(HttpHeaders.USER_AGENT, getUserAgent()); - return transport.configureRequest(request, uri); + return client.configureRequest(request); } - protected T handleResponse(Response response) throws ClientProtocolException, IOException { - return response.handleResponse(response1 -> { - HttpEntity entity = null; - try { - final StatusLine statusLine = response1.getStatusLine(); - entity = response1.getEntity(); - handleResponseStatus(statusLine.getStatusCode(), statusLine.getReasonPhrase()); - return handleResponseEntity(entity); - } finally { - closeResponse(response1, entity); - } - }); + protected T handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + HttpEntity entity = null; + try { + final StatusLine statusLine = response.getStatusLine(); + entity = response.getEntity(); + handleResponseStatus(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + return handleResponseEntity(entity); + } finally { + closeResponse(response, entity); + } } protected T handleResponseEntity(HttpEntity entity) throws IOException { diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/SystemCredentialsProvider.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/SystemCredentialsProvider.java index c3988fae..1572a8e4 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/SystemCredentialsProvider.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/transport/httpclient/SystemCredentialsProvider.java @@ -27,15 +27,15 @@ public class SystemCredentialsProvider extends SystemDefaultCredentialsProvider String domain = ntCredentials.getDomain(); String userName = ntCredentials.getUserName(); String workstation = ntCredentials.getWorkstation(); - String strippedUserName = HttpClientProxyUtil.getNTLMUserName(userName); + String strippedUserName = NTLMDomainUtil.getNTLMUserName(userName); if (domain == null || !strippedUserName.equals(userName)) { - domain = HttpClientProxyUtil.getNTLMUserDomain(userName); + domain = NTLMDomainUtil.getNTLMUserDomain(userName); if (domain != null) { userName = strippedUserName; } } if (workstation == null) { - workstation = HttpClientProxyUtil.getNTLMWorkstation(); + workstation = NTLMDomainUtil.getNTLMWorkstation(); } credentials = new NTCredentials(userName, ntCredentials.getPassword(), workstation, domain); } diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/FallbackTransportFactory.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/FallbackTransportFactory.java index c68a5060..87a4d7f3 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/FallbackTransportFactory.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/FallbackTransportFactory.java @@ -38,11 +38,13 @@ import org.osgi.framework.ServiceReference; public class FallbackTransportFactory implements ITransportFactory { private static final class FallbackTransport implements ITransport { - private ITransport primaryTransport; + private final ITransport primaryTransport; - private final ITransport fallbackTransport; + private ITransport fallbackTransport; - public FallbackTransport(ITransport primaryTransport, ITransport fallbackTransport) { + private boolean primaryDisabled = false; + + FallbackTransport(ITransport primaryTransport, ITransport fallbackTransport) { super(); this.primaryTransport = primaryTransport; this.fallbackTransport = fallbackTransport; @@ -59,11 +61,12 @@ public class FallbackTransportFactory implements ITransportFactory { throws FileNotFoundException, ServiceUnavailableException, CoreException { connectionAttempts++; if (connectionAttempts > 10 && connectionFailures / (double) connectionAttempts > 0.75) { - MarketplaceClientCore.getLog().log(new Status(IStatus.INFO, MarketplaceClientCore.BUNDLE_ID, + MarketplaceClientCore.getLog() + .log(new Status(IStatus.INFO, MarketplaceClientCore.BUNDLE_ID, NLS.bind(Messages.FallbackTransportFactory_disablingTransport, primaryTransport))); - primaryTransport = null; + primaryDisabled = true; } - if (primaryTransport == null) { + if (primaryTransport == null || primaryDisabled) { return fallbackTransport.stream(location, monitor); } InputStream stream; @@ -126,6 +129,8 @@ public class FallbackTransportFactory implements ITransportFactory { boolean fallbackSucceeded = false; try { InputStream fallbackStream = fallbackTransport.stream(location, monitor); + BufferedInputStream buffered = new BufferedInputStream(fallbackStream); + tryBuffer(buffered); fallbackSucceeded = true; String problemKey = ex.getClass().getName() + ": " + ex.getMessage() + "\n\t" //$NON-NLS-1$//$NON-NLS-2$ + ex.getStackTrace()[0]; @@ -136,7 +141,9 @@ public class FallbackTransportFactory implements ITransportFactory { fallbackTransport))); } - return fallbackStream; + return buffered; + } catch (Exception fallbackEx) { + ex.addSuppressed(fallbackEx); } finally { if (!fallbackSucceeded) { //fallback didn't work either - probably something unrelated to transport going on, so don't count this as a transport failure @@ -146,25 +153,46 @@ public class FallbackTransportFactory implements ITransportFactory { } return null; } + + void setFallbackTransport(ITransport fallbackTransport) { + this.fallbackTransport = fallbackTransport; + } + + public ITransport getPrimaryTransport() { + return primaryTransport; + } + + public ITransport getFallbackTransport() { + return fallbackTransport; + } } private ITransportFactory primaryFactory; private ITransportFactory secondaryFactory; + private FallbackTransport transport; + public FallbackTransportFactory() { super(); // ignore } @Override - public ITransport getTransport() { + public synchronized ITransport getTransport() { ITransportFactory delegateFactory = getFallbackFactory(); + ITransport primaryTransport = primaryFactory.getTransport(); if (delegateFactory == null) { - return primaryFactory.getTransport(); + return primaryTransport; } - return new FallbackTransport(primaryFactory.getTransport(), delegateFactory.getTransport()); + ITransport secondaryTransport = delegateFactory.getTransport(); + + if (transport == null || transport.getPrimaryTransport() != primaryTransport + || transport.getFallbackTransport() != secondaryTransport) { + transport = new FallbackTransport(primaryTransport, secondaryTransport); + } + return transport; } public ITransportFactory getFallbackFactory() { diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/HttpUtil.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/HttpUtil.java deleted file mode 100644 index a0bf302b..00000000 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/HttpUtil.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2018 The Eclipse Foundation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Yatta Solutions - initial API and implementation - *******************************************************************************/ -package org.eclipse.epp.internal.mpc.core.util; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.DefaultProxyRoutePlanner; -import org.eclipse.core.net.proxy.IProxyData; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; - -/** - * @author Carsten Reckord - */ -public class HttpUtil { - - public static HttpClient createHttpClient(String baseUri) { - HttpClientBuilder hcBuilder = HttpClients.custom(); - hcBuilder.setUserAgent(MarketplaceClientCore.BUNDLE_ID); - - if (baseUri != null) { - configureProxy(hcBuilder, baseUri); - } - - return hcBuilder.build(); - } - - public static void configureProxy(HttpClientBuilder hcBuilder, String url) { - final IProxyData proxyData = ProxyHelper.getProxyData(url); - if (proxyData != null && !IProxyData.SOCKS_PROXY_TYPE.equals(proxyData.getType())) { - HttpHost proxy = new HttpHost(proxyData.getHost(), proxyData.getPort()); - DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); - hcBuilder.setRoutePlanner(routePlanner); - if (proxyData.isRequiresAuthentication()) { - CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials(new AuthScope(proxyData.getHost(), proxyData.getPort()), - new UsernamePasswordCredentials(proxyData.getUserId(), proxyData.getPassword())); - hcBuilder.setDefaultCredentialsProvider(provider); - } - } - } -} diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyAuthenticator.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyAuthenticator.java deleted file mode 100644 index 30365545..00000000 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyAuthenticator.java +++ /dev/null @@ -1,194 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2018 The Eclipse Foundation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * The Eclipse Foundation - initial API and implementation - *******************************************************************************/ -package org.eclipse.epp.internal.mpc.core.util; - -import java.net.Authenticator; -import java.net.InetAddress; -import java.net.PasswordAuthentication; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.UnknownHostException; -import java.text.MessageFormat; - -import org.eclipse.core.net.proxy.IProxyData; -import org.eclipse.core.net.proxy.IProxyService; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtension; -import org.eclipse.core.runtime.RegistryFactory; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; -import org.eclipse.osgi.util.NLS; - -class ProxyAuthenticator extends Authenticator { - private static final String EGIT_AUTHENTICATOR_CLASS = "org.eclipse.egit.core.EclipseAuthenticator"; //$NON-NLS-1$ - - private final Authenticator delegate; - - private final Authenticator previousAuthenticator; - - public ProxyAuthenticator(Authenticator delegate) { - if (delegate instanceof ProxyAuthenticator) { - delegate = ((ProxyAuthenticator) delegate).getDelegate(); - } - this.previousAuthenticator = delegate; - this.delegate = fixDelegate(delegate); - } - - private static Authenticator fixDelegate(Authenticator delegate) { - if (delegate == null) { - return null; - } - if (EGIT_AUTHENTICATOR_CLASS.equals(delegate.getClass().getName())) { - Authenticator replacement = getPluggedInNonEGitAuthenticator(); - if (replacement != null) { - return replacement; - } - } - return delegate; - } - - private static Authenticator getPluggedInNonEGitAuthenticator() { - @SuppressWarnings("restriction") - IExtension[] extensions = RegistryFactory.getRegistry() - .getExtensionPoint(org.eclipse.core.internal.net.Activator.ID, - org.eclipse.core.internal.net.Activator.PT_AUTHENTICATOR) - .getExtensions(); - if (extensions.length == 0) { - return null; - } - IConfigurationElement config = null; - for (IExtension extension : extensions) { - IConfigurationElement[] configs = extension.getConfigurationElements(); - if (configs.length == 0) { - continue; - } - String className = configs[0].getAttribute("class"); //$NON-NLS-1$ - if (className != null && !EGIT_AUTHENTICATOR_CLASS.equals(className)) { - config = configs[0]; - break; - } - } - if (config != null) { - try { - return (Authenticator) config.createExecutableExtension("class");//$NON-NLS-1$ - } catch (CoreException ex) { - MarketplaceClientCore.error(NLS.bind("Unable to instantiate authenticator {0}", //$NON-NLS-1$ - (new Object[] { config.getDeclaringExtension().getUniqueIdentifier() })), ex); - } - } - return null; - } - - private boolean hostMatches(final IProxyData proxy) { - String proxyHost = proxy.getHost(); - if (proxyHost == null) { - return false; - } - try { - InetAddress requestingAddress = getRequestingSite(); - if (requestingAddress != null) { - final InetAddress proxyAddress = InetAddress.getByName(proxyHost); - return proxyAddress.equals(requestingAddress); - } - } catch (UnknownHostException err) { - return false; - } - String requestingHost = getRequestingHost(); - if (requestingHost != null && requestingHost.equals(proxyHost)) { - return true; - } - return false; - } - - @Override - protected PasswordAuthentication getPasswordAuthentication() { - IProxyService proxyService = ProxyHelper.getProxyService(); - if (proxyService != null && proxyService.isProxiesEnabled()) { - URL requestingURL = getRequestingURL(); - IProxyData[] proxies; - if (requestingURL == null) { - proxies = proxyService.getProxyData(); - } else { - try { - proxies = proxyService.select(requestingURL.toURI()); - } catch (URISyntaxException e) { - proxies = proxyService.getProxyData(); - } - } - - for (IProxyData proxyData : proxies) { - // make sure we don't hand out credentials to the wrong proxy - if (proxyData.isRequiresAuthentication() && proxyData.getPort() == getRequestingPort() - && hostMatches(proxyData)) { - String userId = proxyData.getUserId(); - String password = proxyData.getPassword(); - if (userId != null && password != null) { - return new PasswordAuthentication(userId, password.toCharArray()); - } - } - } - } - if (delegate != null) { - // Pass on to previously registered authenticator - // Eclipse UI bundle registers one to query credentials from user - try { - Authenticator.setDefault(delegate); - String requestingHost = getRequestingHost(); - InetAddress requestingSite = getRequestingSite(); - int requestingPort = getRequestingPort(); - String requestingProtocol = getRequestingProtocol(); - String requestingPrompt = getRequestingPrompt(); - String requestingScheme = getRequestingScheme(); - URL requestingURL = getRequestingURL(); - RequestorType requestorType = getRequestorType(); - if (requestingSite == null) { - try { - requestingSite = InetAddress.getByName(requestingHost); - } catch (Exception ex) { - //ignore - } - } - if (requestingPrompt == null) { - //Help the Eclipse UI password dialog with its prompt - String promptHost = requestingSite == null ? String.format("%s:%s", requestingHost, requestingPort) //$NON-NLS-1$ - : requestingHost == null ? requestingSite.getHostName() : requestingHost; - String promptType = requestorType.toString().toLowerCase(); - requestingPrompt = MessageFormat.format(Messages.ProxyAuthenticator_prompt, requestingScheme, - promptType, promptHost); - } - return Authenticator.requestPasswordAuthentication(requestingHost, requestingSite, requestingPort, - requestingProtocol, requestingPrompt, requestingScheme, requestingURL, requestorType); - } finally { - Authenticator.setDefault(this); - } - } - return null; - } - - public Authenticator getDelegate() { - return delegate; - } - - public void install() { - Authenticator.setDefault(this); - } - - public void uninstall() { - synchronized (Authenticator.class) { - Authenticator defaultAuthenticator = ProxyHelper.getDefaultAuthenticator(); - if (defaultAuthenticator == this) { - Authenticator.setDefault(previousAuthenticator); - } - } - } -}
\ No newline at end of file diff --git a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyHelper.java b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyHelper.java index 26df427e..9e16e226 100644 --- a/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyHelper.java +++ b/org.eclipse.epp.mpc.core/src/org/eclipse/epp/internal/mpc/core/util/ProxyHelper.java @@ -12,70 +12,18 @@ *******************************************************************************/ package org.eclipse.epp.internal.mpc.core.util; -import java.lang.reflect.Field; -import java.net.Authenticator; import java.net.URI; import java.net.URISyntaxException; import org.eclipse.core.net.proxy.IProxyData; import org.eclipse.core.net.proxy.IProxyService; -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.osgi.util.tracker.ServiceTracker; /** * @author Carsten Reckord */ public class ProxyHelper { -// private static ProxyAuthenticator authenticator; - @SuppressWarnings("rawtypes") - private static ServiceTracker proxyServiceTracker; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static synchronized void acquireProxyService() { - if (proxyServiceTracker == null) { - proxyServiceTracker = new ServiceTracker(MarketplaceClientCorePlugin.getBundle().getBundleContext(), - IProxyService.class.getName(), null); - proxyServiceTracker.open(); - } -// installAuthenticator(); - } - - public static void installAuthenticator() { -// synchronized (Authenticator.class) { -// Authenticator defaultAuthenticator = getDefaultAuthenticator(); -// if (authenticator == null || authenticator != defaultAuthenticator) { -// if (defaultAuthenticator instanceof ProxyAuthenticator) { -// authenticator = (ProxyAuthenticator) defaultAuthenticator; -// } else { -// authenticator = new ProxyAuthenticator(defaultAuthenticator); -// } -// authenticator.install(); -// } -// } - } - - public static synchronized void releaseProxyService() { -// uninstallAuthenticator(); - if (proxyServiceTracker != null) { - proxyServiceTracker.close(); - } - } - - public static void uninstallAuthenticator() { -// synchronized (Authenticator.class) { -// if (authenticator != null) { -// authenticator.uninstall(); -// authenticator = null; -// } -// } - } - - public static IProxyData getProxyData(String url) { - final IProxyService proxyService = getProxyService(); + public static IProxyData getProxyData(String url, IProxyService proxyService) { if (proxyService != null) { URI uri; try { @@ -88,8 +36,7 @@ public class ProxyHelper { return null; } - public static IProxyData getProxyData(URI uri) { - final IProxyService proxyService = getProxyService(); + public static IProxyData getProxyData(URI uri, IProxyService proxyService) { if (proxyService != null) { return doGetProxyData(proxyService, uri); } @@ -111,28 +58,4 @@ public class ProxyHelper { } return null; } - - protected static IProxyService getProxyService() { - return proxyServiceTracker == null ? null : (IProxyService) proxyServiceTracker.getService(); - } - - static Authenticator getDefaultAuthenticator() { - try { - final Field authenticatorField = Authenticator.class.getDeclaredField("theAuthenticator"); //$NON-NLS-1$ - final boolean accessible = authenticatorField.isAccessible(); - try { - if (!accessible) { - authenticatorField.setAccessible(true); - } - return (Authenticator) authenticatorField.get(null); - } finally { - if (!accessible) { - authenticatorField.setAccessible(false); - } - } - } catch (Exception e) { - MarketplaceClientCore.getLog().log(new Status(IStatus.WARNING, MarketplaceClientCore.BUNDLE_ID, Messages.ProxyHelper_replacingAuthenticator, e)); - } - return null; - } } 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 index 5a0912d1..74738bbd 100644 --- 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 @@ -25,6 +25,7 @@ import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; +import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentConstants; @@ -186,4 +187,11 @@ public class ServiceUtil { ServiceReference<T> reference = registration.getReference(); return reference == null ? null : getService(reference); } + + public static <T> T getService(Class<?> context, Class<T> serviceType) { + BundleContext bundleContext = FrameworkUtil.getBundle(context).getBundleContext(); + ServiceReference<T> serviceReference = bundleContext == null ? null + : bundleContext.getServiceReference(serviceType); + return serviceReference == null ? null : bundleContext.getService(serviceReference); + } } 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 298e611d..3ebbae02 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 @@ -44,6 +44,9 @@ import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@@ -87,6 +90,10 @@ public abstract class TransportFactory implements ITransportFactory { .getProperty(ECF_EXCLUDES_PROPERTY);
if (excludeContributors != null && excludeContributors.contains(ECF_HTTPCLIENT4_TRANSPORT_ID)) {
disabledTransportsStr += "," + HTTP_TRANSPORT_WRAPPER_ID + "," + HTTP_TRANSPORT_FACTORY_ID; //$NON-NLS-1$//$NON-NLS-2$
+ } else if (disabledTransportsStr.contains(HTTP_TRANSPORT_WRAPPER_ID)) {
+ disabledTransportsStr += "," + HTTP_TRANSPORT_FACTORY_ID; //$NON-NLS-1$
+ } else if (disabledTransportsStr.contains(HTTP_TRANSPORT_FACTORY_ID)) {
+ disabledTransportsStr += "," + HTTP_TRANSPORT_WRAPPER_ID; //$NON-NLS-1$
}
Set<String> disabledTransports = new HashSet<>();
StringBuilder bldr = new StringBuilder("(&"); //$NON-NLS-1$
@@ -105,6 +112,8 @@ public abstract class TransportFactory implements ITransportFactory { return disabledTransportsFilter;
}
+ @Component(name = "org.eclipse.epp.mpc.core.transportfactory.legacy", property = {
+ "org.eclipse.epp.mpc.core.service.transport.legacy:Boolean=true", "service.ranking:Integer=-2147483647" })
public static final class LegacyFactory implements ITransportFactory {
private ITransportFactory delegate;
@@ -122,6 +131,7 @@ public abstract class TransportFactory implements ITransportFactory { return delegate.getTransport();
}
+ @Activate
public void activate(ComponentContext context) throws InvalidSyntaxException {
BundleContext bundleContext = context.getBundleContext();
Collection<ServiceReference<ITransportFactory>> serviceReferences = bundleContext.getServiceReferences(
@@ -152,6 +162,7 @@ public abstract class TransportFactory implements ITransportFactory { delegateReference = null;
}
+ @Deactivate
public void deactivate(ComponentContext context) {
delegate = null;
if (delegateReference != null) {
@@ -245,7 +256,10 @@ public abstract class TransportFactory implements ITransportFactory { lastFallbackTransport = null;
}
}
- return transportService.getTransport();
+ org.eclipse.epp.mpc.core.service.ITransport transport = transportService.getTransport();
+ if (transport != null) {
+ return transport;
+ }
} finally {
context.ungetService(serviceReference);
}
@@ -264,8 +278,15 @@ public abstract class TransportFactory implements ITransportFactory { for (ITransportFactory factory : listAvailableFactories()) {
try {
org.eclipse.epp.mpc.core.service.ITransport transport = factory.getTransport();
- logTransportServiceFallback(serviceError, defaultServiceReference, null, factory);
- return transport;
+ if (transport != null) {
+ logTransportServiceFallback(serviceError, defaultServiceReference, null, factory);
+ return transport;
+ } else {
+ serviceError.add(new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID,
+ NLS.bind(Messages.TransportFactory_LegacyFallbackCreationError,
+ factory.getClass().getName()),
+ new NullPointerException("Factory returned null transport")));
+ }
} catch (Exception ex) {
serviceError.add(new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID,
NLS.bind(Messages.TransportFactory_LegacyFallbackCreationError, factory.getClass().getName()), ex));
@@ -390,17 +411,22 @@ public abstract class TransportFactory implements ITransportFactory { return factories;
}
+ private ITransport transport;
+
@Override
@SuppressWarnings("deprecation")
- public ITransport getTransport() {
- return (location, monitor) -> {
- try {
- return invokeStream(location, monitor);
- } catch (Exception e) {
- handleStreamExceptions(e);
- }
- return null;
- };
+ public synchronized ITransport getTransport() {
+ if (transport == null && isAvailable()) {
+ transport = (location, monitor) -> {
+ try {
+ return invokeStream(location, monitor);
+ } catch (Exception e) {
+ handleStreamExceptions(e);
+ }
+ return null;
+ };
+ }
+ return transport;
}
protected abstract boolean isAvailable();
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 index 410079b0..73a2be7b 100644 --- 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 @@ -13,7 +13,7 @@ *******************************************************************************/ package org.eclipse.epp.mpc.core.service; -import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; +import org.eclipse.epp.internal.mpc.core.ServiceHelperImpl; /** * Convenience class to access marketplace-related OSGi services. @@ -25,7 +25,7 @@ import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; public abstract class ServiceHelper { private static ServiceHelper getInstance() { - return MarketplaceClientCorePlugin.getDefault().getServiceHelper(); + return ServiceHelperImpl.getImplInstance(); } protected abstract IMarketplaceServiceLocator doGetMarketplaceServiceLocator(); 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 7d237da2..d0ce03a5 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 @@ -20,14 +20,11 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Constructor; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -44,12 +41,9 @@ import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.config.AuthSchemes; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.fluent.Response; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Lookup; @@ -59,8 +53,10 @@ import org.apache.http.protocol.HttpContext; 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.ServiceHelperImpl; import org.eclipse.epp.internal.mpc.core.transport.httpclient.ChainedCredentialsProvider; import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientCustomizer; +import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientService; import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransport; import org.eclipse.epp.internal.mpc.core.transport.httpclient.HttpClientTransportFactory; import org.eclipse.epp.internal.mpc.core.transport.httpclient.SynchronizedCredentialsProvider; @@ -78,6 +74,8 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; +import org.mockito.internal.MockitoCore; +import org.mockito.internal.util.MockUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; @@ -120,6 +118,11 @@ public class TransportFactoryTest { System.getProperties().remove("org.eclipse.ecf.provider.filetransfer.excludeContributors"); } + @Before + public void initServiceHelper() { + ServiceHelperImpl.getImplInstance(); + } + @Test public void testRegisteredFactories() throws Exception { BundleContext context = MarketplaceClientCorePlugin.getBundle().getBundleContext(); @@ -234,26 +237,15 @@ public class TransportFactoryTest { createFailingHttpClientTransport().stream(URI.create("http://127.0.0.1:54321"), null); } - private static HttpClientTransport createFailingHttpClientTransport() { - return new HttpClientTransport() { - @Override - protected Response execute(Request request, URI uri) throws ClientProtocolException, IOException { - HttpResponse mockResponse = mockResponse(mockStatusLine(503, "Expected test error"), null); - try { - Constructor<Response> ctor = Response.class.getDeclaredConstructor(HttpResponse.class); - ctor.setAccessible(true); - return ctor.newInstance(mockResponse); - } catch (Exception e) { - try { - fail("Failed to create response"); - } catch (AssertionError ae) { - ae.initCause(e); - throw ae; - } - return null; - } - } - }; + private static HttpClientTransport createFailingHttpClientTransport() throws Exception { + HttpClientTransport transport = new HttpClientTransport(); + HttpClientService mockClient = Mockito.mock(HttpClientService.class); + Mockito.when(mockClient.configureRequest(ArgumentMatchers.any())).thenAnswer(args -> args.getArgument(0)); + Mockito.doReturn(mockResponse(mockStatusLine(503, "Expected test error"), null)).when(mockClient).execute( + ArgumentMatchers.any()); + + transport.bindHttpClientService(mockClient); + return transport; } @Test @@ -262,9 +254,11 @@ public class TransportFactoryTest { HttpClientTransportFactory httpClientFactory = new HttpClientTransportFactory(); httpClientFactory.setTransport(httpClientTransport); + + String expectedMessage = "Secondary transport"; ITransportFactory secondaryFactory = Mockito.mock(ITransportFactory.class); ITransport secondaryTransport = Mockito.mock(ITransport.class); - InputStream expectedResultStream = new ByteArrayInputStream("Secondary transport".getBytes( + InputStream expectedResultStream = new ByteArrayInputStream(expectedMessage.getBytes( StandardCharsets.UTF_8)); Mockito.when(secondaryFactory.getTransport()).thenReturn(secondaryTransport); Mockito.when(secondaryTransport.stream(ArgumentMatchers.<URI> any(), ArgumentMatchers.<IProgressMonitor> any())).thenReturn( @@ -275,7 +269,10 @@ public class TransportFactoryTest { fallbackTransportFactory.setSecondaryFactory(secondaryFactory); InputStream stream = fallbackTransportFactory.getTransport().stream(URI.create("http://127.0.0.1:54321"), null); - assertSame(expectedResultStream, stream); + byte[] resultBytes = new byte[24]; + int read = stream.read(resultBytes); + String actualMessage = new String(resultBytes, 0, read, StandardCharsets.UTF_8); + assertEquals(expectedMessage, actualMessage); } @Test @@ -304,20 +301,33 @@ public class TransportFactoryTest { return new HttpClientTransport(); } + BundleContext clientServiceContext = FrameworkUtil.getBundle(HttpClientService.class).getBundleContext(); List<ServiceRegistration<?>> registrations = new ArrayList<>(); for (int i = 0; i < customizers.length; i++) { + MockitoCore mockitoCore = new MockitoCore(); + for (HttpClientCustomizer customizer : customizers) { + if (MockUtil.isMock(customizer)) { + mockitoCore.clearInvocations(customizer); + } + } HttpClientCustomizer customizer = customizers[i]; Dictionary<String, Object> serviceProperties = ServiceUtil.serviceName( "org.eclipse.epp.mpc.core.transport.http.test.customizer." + i, ServiceUtil.serviceRanking(1000 + i, null)); - ServiceRegistration<?> registration = FrameworkUtil.getBundle(HttpClientCustomizer.class).getBundleContext() + ServiceRegistration<?> registration = clientServiceContext .registerService(HttpClientCustomizer.class, customizer, serviceProperties); registrations.add(registration); } + + ServiceReference<HttpClientService> clientServiceRef = clientServiceContext.getServiceReference( + HttpClientService.class); + HttpClientService clientService = clientServiceContext.getService(clientServiceRef); + HttpClientTransport httpClientTransport; try { httpClientTransport = new HttpClientTransport(); + httpClientTransport.bindHttpClientService(clientService); } finally { |
