Skip to content

Commit

Permalink
Extract the Http specific parts out of the Repository Transport
Browse files Browse the repository at this point in the history
Fix #1887
  • Loading branch information
laeubi committed Dec 19, 2022
1 parent 00cf53f commit df4dab7
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 97 deletions.
2 changes: 1 addition & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The parameter `allowConflictingDependencies` was removed from the target platfor
#### Choosable HTTP transports

Tycho uses a custom P2 transport to download items from updatesites, previously URLConnection was used for this but now the Java HTTP 11 Client is the new default because it supports HTTP/2 now.
To use the old URLConnection one can pass `-Dtycho.p2.transport.type=JavaUrl` to the build.
To use the old URLConnection one can pass `-Dtycho.p2.httptransport.type=JavaUrl` to the build.

Valid values are:
- `JavaUrl` - uses URLConnection to retrieve files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;

@Component(role = HttpCacheConfig.class)
public class DefaultHttpCacheConfig implements HttpCacheConfig, Initializable {
@Component(role = TransportCacheConfig.class)
public class DefaultTransportCacheConfig implements TransportCacheConfig, Initializable {

private boolean offline;
private boolean update;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2022 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.p2maven.transport;

import java.io.File;
import java.io.IOException;
import java.net.URI;

import org.codehaus.plexus.component.annotations.Component;

@Component(role = TransportProtocolHandler.class, hint = "file")
public class FileTransportProtocolHandler implements TransportProtocolHandler {

@Override
public long getLastModified(URI uri) throws IOException {
return getFile(uri).lastModified();
}


@Override
public File getFile(URI remoteFile) throws IOException {
try {
return new File(remoteFile);
} catch (IllegalArgumentException e) {
throw new IOException("Not a valid file URI: " + remoteFile);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,4 @@ public interface HttpCache {
*/
CacheEntry getCacheEntry(URI uri, Logger logger) throws FileNotFoundException;

HttpCacheConfig getCacheConfig();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2022 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.p2maven.transport;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.Objects;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;

@Component(role = TransportProtocolHandler.class, hint = "http")
public class HttpTransportProtocolHandler implements TransportProtocolHandler {

static final String TRANSPORT_TYPE = System.getProperty("tycho.p2.httptransport.type",
Java11HttpTransportFactory.HINT);

@Requirement
Map<String, HttpTransportFactory> transportFactoryMap;
@Requirement
HttpCache httpCache;

@Requirement
Logger logger;

private HttpTransportFactory getTransportFactory() {
return Objects.requireNonNull(transportFactoryMap.get(TRANSPORT_TYPE), "Invalid transport configuration");
}

@Override
public long getLastModified(URI uri) throws IOException {
return httpCache.getCacheEntry(uri, logger).getLastModified(getTransportFactory());
}

@Override
public File getFile(URI remoteFile) throws IOException {
return httpCache.getCacheEntry(remoteFile, logger).getCacheFile(getTransportFactory());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2022 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.p2maven.transport;

import org.codehaus.plexus.component.annotations.Component;

@Component(role = TransportProtocolHandler.class, hint = "https")
public class HttpsTransportProtocolHandler extends HttpTransportProtocolHandler {

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class SharedHttpCacheStorage implements HttpCache {
private static final int MAX_IN_MEMORY = 1000;

@Requirement
HttpCacheConfig cacheConfig;
TransportCacheConfig cacheConfig;

private final Map<File, CacheLine> entryCache;

Expand All @@ -80,11 +80,6 @@ protected boolean removeEldestEntry(final Map.Entry<File, CacheLine> eldest) {
};
}

@Override
public HttpCacheConfig getCacheConfig() {
return cacheConfig;
}

/**
* Fetches the cache entry for this URI
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import java.io.File;

public interface HttpCacheConfig {
public interface TransportCacheConfig {

boolean isOffline();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.eclipse.tycho.p2maven.transport;

import java.io.File;
import java.io.IOException;
import java.net.URI;

public interface TransportProtocolHandler {

long getLastModified(URI uri) throws IOException;

File getFile(URI remoteFile) throws IOException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.net.URLConnection;
import java.text.NumberFormat;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
Expand All @@ -49,8 +48,7 @@ public class TychoRepositoryTransport extends org.eclipse.equinox.internal.p2.re
implements IAgentServiceFactory {

private static final int MAX_DOWNLOAD_THREADS = Integer.getInteger("tycho.p2.transport.max-download-threads", 4);
static final String TRANSPORT_TYPE = System.getProperty("tycho.p2.transport.type",
Java11HttpTransportFactory.HINT);

private static final boolean DEBUG_REQUESTS = Boolean.getBoolean("tycho.p2.transport.debug");

private static final Executor DOWNLOAD_EXECUTOR = Executors.newFixedThreadPool(MAX_DOWNLOAD_THREADS, new ThreadFactory() {
Expand All @@ -67,13 +65,14 @@ public Thread newThread(Runnable r) {

private NumberFormat numberFormat = NumberFormat.getNumberInstance();

@Requirement
Map<String, HttpTransportFactory> transportFactoryMap;

@Requirement
Logger logger;

@Requirement
HttpCache httpCache;
TransportCacheConfig cacheConfig;

@Requirement(role = TransportProtocolHandler.class)
Map<String, TransportProtocolHandler> transportProtocolHandlers;

private LongAdder requests = new LongAdder();
private LongAdder indexRequests = new LongAdder();
Expand All @@ -94,15 +93,15 @@ public IStatus download(URI toDownload, OutputStream target, long startPos, IPro
@Override
public IStatus download(URI toDownload, OutputStream target, IProgressMonitor monitor) {
String id = "p2"; // TODO we might compute the id from the IRepositoryIdManager based on the URI?
if (httpCache.getCacheConfig().isInteractive()) {
if (cacheConfig.isInteractive()) {
logger.info("Downloading from " + id + ": " + toDownload);
}
try {
DownloadStatusOutputStream statusOutputStream = new DownloadStatusOutputStream(target,
"Download of " + toDownload);
IOUtils.copy(stream(toDownload, monitor), statusOutputStream);
DownloadStatus downloadStatus = statusOutputStream.getStatus();
if (httpCache.getCacheConfig().isInteractive()) {
if (cacheConfig.isInteractive()) {
logger.info(
"Downloaded from " + id + ": " + toDownload + " ("
+ FileUtils.byteCountToDisplaySize(downloadStatus.getFileSize())
Expand Down Expand Up @@ -138,13 +137,16 @@ public synchronized InputStream stream(URI toDownload, IProgressMonitor monitor)
indexRequests.increment();
}
try {
File cachedFile = getCachedFile(toDownload);
if (cachedFile != null) {
if (DEBUG_REQUESTS) {
logger.debug(" --> routed through http-cache ...");
}
return new FileInputStream(cachedFile);
}
TransportProtocolHandler handler = getHandler(toDownload);
if (handler != null) {
File cachedFile = handler.getFile(toDownload);
if (cachedFile != null) {
if (DEBUG_REQUESTS) {
logger.debug(" --> routed through handler " + handler.getClass().getSimpleName() + " ...");
}
return new FileInputStream(cachedFile);
}
}
return toDownload.toURL().openStream();
} catch (FileNotFoundException e) {
if (DEBUG_REQUESTS) {
Expand All @@ -165,53 +167,42 @@ public synchronized InputStream stream(URI toDownload, IProgressMonitor monitor)
}
}

TransportProtocolHandler getHandler(URI uri) {
String scheme = uri.getScheme();
if (scheme != null) {
String lc = scheme.toLowerCase();
TransportProtocolHandler handler = transportProtocolHandlers.get(lc);
if (handler != null) {
return handler;
}
}
return null;
}

@Override
public long getLastModified(URI toDownload, IProgressMonitor monitor)
throws CoreException, FileNotFoundException, AuthenticationFailedException {
//TODO P2 cache manager relies on this method to throw an exception to work correctly
try {
if (isHttp(toDownload)) {
return httpCache.getCacheEntry(toDownload, logger)
.getLastModified(getTransportFactory());
}
URLConnection connection = toDownload.toURL().openConnection();
long lastModified = connection.getLastModified();
connection.getInputStream().close();
return lastModified;
} catch (FileNotFoundException e) {
throw e;
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, TychoRepositoryTransport.class.getName(),
"download from " + toDownload + " failed", e));
}
try {
TransportProtocolHandler handler = getHandler(toDownload);
if (handler != null) {
return handler.getLastModified(toDownload);
}
URLConnection connection = toDownload.toURL().openConnection();
long lastModified = connection.getLastModified();
connection.getInputStream().close();
return lastModified;
} catch (FileNotFoundException e) {
throw e;
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, TychoRepositoryTransport.class.getName(),
"download from " + toDownload + " failed", e));
}
}

private HttpTransportFactory getTransportFactory() {
return Objects.requireNonNull(transportFactoryMap.get(TRANSPORT_TYPE), "Invalid transport configuration");
}

@Override
public Object createService(IProvisioningAgent agent) {
return this;
}

public HttpCache getHttpCache() {
return httpCache;
}

public File getCachedFile(URI remoteFile) throws IOException {

if (isHttp(remoteFile)) {
return httpCache.getCacheEntry(remoteFile, logger).getCacheFile(getTransportFactory());
}
return null;
}

public static boolean isHttp(URI remoteFile) {
String scheme = remoteFile.getScheme();
return scheme != null && scheme.toLowerCase().startsWith("http");
}

public static Executor getDownloadExecutor() {
return DOWNLOAD_EXECUTOR;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*******************************************************************************/
package org.eclipse.tycho.p2maven.transport;

import java.util.concurrent.atomic.AtomicBoolean;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
Expand All @@ -30,24 +32,26 @@ public class TychoRepositoryTransportAgentFactory implements IAgentServiceFactor
private Logger logger;

@Requirement
HttpCache cache;
TransportCacheConfig config;

@Requirement(hint = "tycho")
org.eclipse.equinox.internal.p2.repository.Transport repositoryTransport;

private AtomicBoolean infoPrinted = new AtomicBoolean();


@Override
public Object createService(IProvisioningAgent agent) {
HttpCacheConfig config = cache.getCacheConfig();
logger.info("### Using TychoRepositoryTransport for remote P2 access ###");
logger.info(" Cache location: " + config.getCacheLocation());
logger.info(" Transport mode: " + (config.isOffline() ? "offline" : "online"));
logger.info(" Transport type: " + TychoRepositoryTransport.TRANSPORT_TYPE);
logger.info(" Update mode: " + (config.isUpdate() ? "forced" : "cache first"));
logger.info(" Minimum cache duration: " + SharedHttpCacheStorage.MIN_CACHE_PERIOD + " minutes");
logger.info(
" (you can configure this with -Dtycho.p2.transport.min-cache-minutes=<desired minimum cache duration>)");

if (infoPrinted.compareAndSet(false, true)) {
logger.info("### Using TychoRepositoryTransport for remote P2 access ###");
logger.info(" Cache location: " + config.getCacheLocation());
logger.info(" Transport mode: " + (config.isOffline() ? "offline" : "online"));
logger.info(" Http Transport type: " + HttpTransportProtocolHandler.TRANSPORT_TYPE);
logger.info(" Update mode: " + (config.isUpdate() ? "forced" : "cache first"));
logger.info(" Minimum cache duration: " + SharedHttpCacheStorage.MIN_CACHE_PERIOD + " minutes");
logger.info(
" (you can configure this with -Dtycho.p2.transport.min-cache-minutes=<desired minimum cache duration>)");
}
return repositoryTransport;
}

Expand Down
Loading

0 comments on commit df4dab7

Please sign in to comment.