blob: de29ed4004733125bbe99833f16aec04cc79bfb1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 The Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Eclipse Foundation - initial API and implementation
* Yatta Solutions - bug 432803: public API
*******************************************************************************/
package org.eclipse.epp.internal.mpc.core.util;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.NoHttpResponseException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin;
import org.eclipse.epp.internal.mpc.core.service.ServiceUnavailableException;
import org.eclipse.epp.mpc.core.service.ITransportFactory;
import org.eclipse.epp.mpc.core.service.ServiceHelper;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Factory to retrieve Transport instances of p2. Will delegate to version-dependent implementations.
*
* @author David Green
* @author Benjamin Muskalla
* @author Carsten Reckord
*/
public abstract class TransportFactory implements ITransportFactory {
public static final String LEGACY_TRANSPORT_KEY = "org.eclipse.epp.mpc.core.service.transport.legacy"; //$NON-NLS-1$
public static final String LEGACY_TRANSPORT_COMPONENT_NAME = "org.eclipse.epp.mpc.core.transportfactory.legacy"; //$NON-NLS-1$
private static final String[] factoryClasses = new String[] { //
"org.eclipse.epp.internal.mpc.core.util.P2TransportFactory", // //$NON-NLS-1$
"org.eclipse.epp.internal.mpc.core.util.Eclipse36TransportFactory", // //$NON-NLS-1$
"org.eclipse.epp.internal.mpc.core.util.JavaPlatformTransportFactory" }; //$NON-NLS-1$
public static final class LegacyFactory implements ITransportFactory {
private ITransportFactory delegate;
private ServiceReference<ITransportFactory> delegateReference;
public LegacyFactory() {
}
public ITransportFactory getDelegate() {
return delegate;
}
public org.eclipse.epp.mpc.core.service.ITransport getTransport() {
return delegate.getTransport();
}
public void activate(ComponentContext context) throws InvalidSyntaxException {
BundleContext bundleContext = context.getBundleContext();
Collection<ServiceReference<ITransportFactory>> serviceReferences = bundleContext.getServiceReferences(
ITransportFactory.class,
"(&(" + LEGACY_TRANSPORT_KEY + "=true)" //$NON-NLS-1$//$NON-NLS-2$
+ "(!(" + ComponentConstants.COMPONENT_NAME + "=" + LEGACY_TRANSPORT_COMPONENT_NAME //$NON-NLS-1$//$NON-NLS-2$
+ ")))"); //$NON-NLS-1$
if (!serviceReferences.isEmpty()) {
for (ServiceReference<ITransportFactory> serviceReference : serviceReferences) {
ITransportFactory service = bundleContext.getService(serviceReference);
if (service instanceof TransportFactory) {
delegate = service;
delegateReference = serviceReference;
return;
} else {
bundleContext.ungetService(serviceReference);
}
}
}
List<ITransportFactory> availableFactories = listAvailableFactories();
if (availableFactories.isEmpty()) {
context.disableComponent(LEGACY_TRANSPORT_COMPONENT_NAME);
throw new IllegalStateException(Messages.TransportFactory_NoLegacyTransportFactoriesError);
}
delegate = availableFactories.get(0);
delegateReference = null;
}
public void deactivate(ComponentContext context) {
delegate = null;
if (delegateReference != null) {
context.getBundleContext().ungetService(delegateReference);
delegateReference = null;
}
}
}
public static class LegacyTransportFactoryTracker extends ServiceTracker<ITransportFactory, TransportFactory> {
public LegacyTransportFactoryTracker(final BundleContext context) {
super(context, ITransportFactory.class, new LegacyTransportFactoryTrackerCustomizer(context));
}
}
public static class LegacyTransportFactoryTrackerCustomizer
implements ServiceTrackerCustomizer<ITransportFactory, TransportFactory> {
private final BundleContext context;
private final Map<ServiceReference<ITransportFactory>, TransportFactory> trackedServices = new HashMap<ServiceReference<ITransportFactory>, TransportFactory>();
private LegacyTransportFactoryTrackerCustomizer(BundleContext context) {
this.context = context;
}
public TransportFactory addingService(ServiceReference<ITransportFactory> reference) {
Object legacyProperty = reference.getProperty(TransportFactory.LEGACY_TRANSPORT_KEY);
if (!Boolean.parseBoolean(String.valueOf(legacyProperty))) {
return null;
}
ITransportFactory service = context.getService(reference);
if (service instanceof TransportFactory.LegacyFactory) {
TransportFactory.LegacyFactory legacyFactory = (TransportFactory.LegacyFactory) service;
service = legacyFactory.getDelegate();
}
if (service instanceof TransportFactory) {
TransportFactory transportFactory = (TransportFactory) service;
if (!trackedServices.containsValue(transportFactory)) {
trackedServices.put(reference, transportFactory);
return transportFactory;
}
}
return null;
}
public void modifiedService(ServiceReference<ITransportFactory> reference, TransportFactory service) {
// ignore
}
public void removedService(ServiceReference<ITransportFactory> reference, TransportFactory service) {
trackedServices.remove(reference);
}
}
/**
* @deprecated use registered {@link ITransportFactory} OSGi service
* @see ServiceHelper#getTransportFactory()
*/
@Deprecated
public static synchronized TransportFactory instance() {
TransportFactory legacyTransportFactory = MarketplaceClientCorePlugin.getDefault()
.getServiceHelper()
.getLegacyTransportFactory();
if (legacyTransportFactory == null) {
throw new IllegalStateException();
}
return legacyTransportFactory;
}
public static org.eclipse.epp.mpc.core.service.ITransport createTransport() {
//search for registered factory service
BundleContext context = MarketplaceClientCorePlugin.getBundle().getBundleContext();
ServiceReference<ITransportFactory> serviceReference = context.getServiceReference(ITransportFactory.class);
if (serviceReference != null) {
ITransportFactory transportService = context.getService(serviceReference);
if (transportService != null) {
try {
return transportService.getTransport();
} finally {
context.ungetService(serviceReference);
}
}
}
throw new IllegalStateException();
}
public static List<ITransportFactory> listAvailableFactories() {
List<ITransportFactory> factories = new ArrayList<ITransportFactory>();
for (String factoryClass : factoryClasses) {
TransportFactory factory;
try {
factory = (TransportFactory) Class.forName(factoryClass, true, TransportFactory.class.getClassLoader())
.newInstance();
} catch (Throwable t) {
// ignore
continue;
}
try {
if (factory.isAvailable()) {
factories.add(factory);
}
} catch (Throwable t) {
MarketplaceClientCore.getLog().log(new Status(IStatus.WARNING, MarketplaceClientCore.BUNDLE_ID,
Messages.TransportFactory_transportAvailabilityError, t));
}
}
return factories;
}
@SuppressWarnings("deprecation")
public ITransport getTransport() {
return new ITransport() {
public InputStream stream(URI location, IProgressMonitor monitor) throws FileNotFoundException,
org.eclipse.epp.mpc.core.service.ServiceUnavailableException, CoreException {
try {
return invokeStream(location, monitor);
} catch (Exception e) {
handleStreamExceptions(e);
}
return null;
}
};
}
protected abstract boolean isAvailable();
protected abstract InputStream invokeStream(URI location, IProgressMonitor monitor) throws Exception;
@SuppressWarnings("deprecation")
protected void handleStreamExceptions(Exception e) throws ServiceUnavailableException, CoreException,
FileNotFoundException {
if (e instanceof InvocationTargetException) {
InvocationTargetException targetException = (InvocationTargetException) e;
Throwable cause = targetException.getCause();
if (cause instanceof CoreException) {
CoreException coreCause = (CoreException) cause;
handleServiceUnavailable(coreCause);
throw coreCause;
} else if (cause instanceof FileNotFoundException) {
throw (FileNotFoundException) cause;
}
} else {
throw new CoreException(new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID, e.getMessage(), e));
}
}
@SuppressWarnings("deprecation")
protected static void handleServiceUnavailable(CoreException e) throws ServiceUnavailableException {
if (e.getStatus().getCode() == 1002) { //failed to read
Throwable cause = e.getCause();
if (cause != null) {
if (cause instanceof NoHttpResponseException || cause.getMessage() != null
&& cause.getMessage().indexOf("503") != -1) { //$NON-NLS-1$
throw new ServiceUnavailableException(new Status(IStatus.ERROR, MarketplaceClientCore.BUNDLE_ID,
503, Messages.DefaultMarketplaceService_serviceUnavailable503, e));
}
}
}
}
}