Skip to content

Commit

Permalink
Extract the caching part into plexus-components
Browse files Browse the repository at this point in the history
  • Loading branch information
laeubi committed Nov 22, 2022
1 parent b4fe154 commit 42397c7
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 113 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*******************************************************************************
* 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 org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
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 {

private boolean offline;
private boolean update;

@Requirement
private LegacySupport legacySupport;
private File cacheLocation;

@Override
public void initialize() throws InitializationException {
File repoDir;
MavenSession session = legacySupport.getSession();
if (session == null) {
repoDir = RepositorySystem.defaultUserLocalRepository;
offline = false;
update = false;
} else {
offline = session.isOffline();
repoDir = new File(session.getLocalRepository().getBasedir());
update = session.getRequest().isUpdateSnapshots();
}

cacheLocation = new File(repoDir, ".cache/tycho");
cacheLocation.mkdirs();
}

@Override
public boolean isOffline() {
return offline;
}

@Override
public boolean isUpdate() {
return update;
}

@Override
public File getCacheLocation() {
return cacheLocation;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* 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.FileNotFoundException;
import java.net.URI;

import org.codehaus.plexus.logging.Logger;

public interface HttpCache {

/**
* Fetches the cache entry for this URI
*
* @param uri
* @return
* @throws FileNotFoundException
* if the URI is know to be not found
*/
CacheEntry getCacheEntry(URI uri, Logger logger) throws FileNotFoundException;

HttpCacheConfig getCacheConfig();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* 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;

public interface HttpCacheConfig {

boolean isOffline();

boolean isUpdate();

File getCacheLocation();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class RemoteArtifactRepositoryManagerAgentFactory implements IAgentServic
@Requirement
Logger logger;

@Requirement
IRepositoryIdManager repositoryIdManager;

@Override
public Object createService(IProvisioningAgent agent) {
IArtifactRepositoryManager plainRepoManager = (IArtifactRepositoryManager) new ArtifactRepositoryComponent()
Expand All @@ -35,8 +38,7 @@ public Object createService(IProvisioningAgent agent) {
plainRepoManager = new P2MirrorDisablingArtifactRepositoryManager(plainRepoManager,
logger);
}
IRepositoryIdManager loadingHelper = agent.getService(IRepositoryIdManager.class);
return new RemoteArtifactRepositoryManager(plainRepoManager, loadingHelper);
return new RemoteArtifactRepositoryManager(plainRepoManager, repositoryIdManager);
}

private boolean getDisableP2MirrorsConfiguration() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ public class RemoteMetadataRepositoryManagerAgentFactory implements IAgentServic
@Requirement
Logger logger;

@Requirement
IRepositoryIdManager repositoryIdManager;

@Override
public Object createService(IProvisioningAgent agent) {
IMetadataRepositoryManager plainMetadataRepoManager = (IMetadataRepositoryManager) new MetadataRepositoryComponent()
.createService(agent);
IRepositoryIdManager loadingHelper = agent.getService(IRepositoryIdManager.class);
return new RemoteMetadataRepositoryManager(plainMetadataRepoManager, loadingHelper, logger);
return new RemoteMetadataRepositoryManager(plainMetadataRepoManager, repositoryIdManager, logger);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,27 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.equinox.internal.p2.repository.AuthenticationFailedException;

public class SharedHttpCacheStorage {
@Component(role = HttpCache.class)
public class SharedHttpCacheStorage implements HttpCache {

/**
private static final int MAX_CACHE_LINES = Integer.getInteger("tycho.p2.transport.max-cache-lines", 1000);
/**
* Assumes the following minimum caching period for remote files in minutes
*/
//TODO can we sync this with the time where maven updates snapshots?
Expand All @@ -56,18 +58,17 @@ public class SharedHttpCacheStorage {

private static final String ETAG_HEADER = "ETag";

private static final Map<CacheConfig, SharedHttpCacheStorage> storageMap = new HashMap<>();

private static final int MAX_IN_MEMORY = 1000;

@Requirement
HttpCacheConfig cacheConfig;

private final Map<File, CacheLine> entryCache;

private CacheConfig cacheConfig;

private SharedHttpCacheStorage(CacheConfig cacheConfig) {
public SharedHttpCacheStorage() {

this.cacheConfig = cacheConfig;
entryCache = new LinkedHashMap<>(100, 0.75f, true) {
entryCache = new LinkedHashMap<>(MAX_CACHE_LINES, 0.75f, true) {

private static final long serialVersionUID = 1L;

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

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

/**
* Fetches the cache entry for this URI
*
Expand All @@ -87,9 +93,10 @@ protected boolean removeEldestEntry(final Map.Entry<File, CacheLine> eldest) {
* @throws FileNotFoundException
* if the URI is know to be not found
*/
@Override
public CacheEntry getCacheEntry(URI uri, Logger logger) throws FileNotFoundException {
CacheLine cacheLine = getCacheLine(uri);
if (!cacheConfig.update) { //if not updates are forced ...
if (!cacheConfig.isUpdate()) { // if not updates are forced ...
int code = cacheLine.getResponseCode();
if (code == HttpURLConnection.HTTP_NOT_FOUND) {
throw new FileNotFoundException(uri.toASCIIString());
Expand All @@ -103,7 +110,7 @@ public CacheEntry getCacheEntry(URI uri, Logger logger) throws FileNotFoundExcep
@Override
public long getLastModified(HttpTransportFactory transportFactory)
throws IOException {
if (cacheConfig.offline) {
if (cacheConfig.isOffline()) {
return cacheLine.getLastModified(uri, transportFactory,
SharedHttpCacheStorage::mavenIsOffline, logger);
}
Expand All @@ -113,7 +120,7 @@ public long getLastModified(HttpTransportFactory transportFactory)
//for not found and failed authentication we can't do anything useful
throw e;
} catch (IOException e) {
if (!cacheConfig.update && cacheLine.getResponseCode() > 0) {
if (!cacheConfig.isUpdate() && cacheLine.getResponseCode() > 0) {
//if we have something cached, use that ...
logger.warn("Request to " + uri + " failed, trying cache instead...");
return cacheLine.getLastModified(uri, transportFactory, nil -> e, logger);
Expand All @@ -125,7 +132,7 @@ public long getLastModified(HttpTransportFactory transportFactory)
@Override
public File getCacheFile(HttpTransportFactory transportFactory)
throws IOException {
if (cacheConfig.offline) {
if (cacheConfig.isOffline()) {
return cacheLine.getFile(uri, transportFactory,
SharedHttpCacheStorage::mavenIsOffline, logger);
}
Expand All @@ -135,7 +142,7 @@ public File getCacheFile(HttpTransportFactory transportFactory)
//for not found and failed authentication we can't do anything useful
throw e;
} catch (IOException e) {
if (!cacheConfig.update && cacheLine.getResponseCode() > 0) {
if (!cacheConfig.isUpdate() && cacheLine.getResponseCode() > 0) {
//if we have something cached, use that ...
logger.warn("Request to " + uri + " failed, trying cache instead...");
return cacheLine.getFile(uri, transportFactory, nil -> e, logger);
Expand All @@ -148,7 +155,8 @@ public File getCacheFile(HttpTransportFactory transportFactory)
}

private synchronized CacheLine getCacheLine(URI uri) {
File file = new File(cacheConfig.location, uri.normalize().toASCIIString().replace(':', '/').replace('?', '/')
File file = new File(cacheConfig.getCacheLocation(), uri.normalize().toASCIIString().replace(':', '/')
.replace('?', '/')
.replace('&', '/').replaceAll("/+", "/"));
File location;
try {
Expand Down Expand Up @@ -292,7 +300,7 @@ public synchronized File getFile(URI uri, HttpTransportFactory transportFactory,
}

private boolean mustValidate() {
if (cacheConfig.update) {
if (cacheConfig.isUpdate()) {
//user enforced validation
return true;
}
Expand Down Expand Up @@ -429,42 +437,8 @@ private static boolean isNotFound(int code) {
return code == HttpURLConnection.HTTP_NOT_FOUND;
}

public static SharedHttpCacheStorage getStorage(File location, boolean offline, boolean update) {
return storageMap.computeIfAbsent(new CacheConfig(location, offline, update), SharedHttpCacheStorage::new);
}

private static IOException mavenIsOffline(URI uri) {
return new IOException("maven is currently in offline mode requested URL " + uri + " does not exist locally!");
}

private static final class CacheConfig {

private final File location;
private final boolean offline;
private final boolean update;

public CacheConfig(File location, boolean offline, boolean update) {
this.location = location;
this.offline = offline;
this.update = update;
}

@Override
public int hashCode() {
return Objects.hash(location, offline, update);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheConfig other = (CacheConfig) obj;
return Objects.equals(location, other.location) && offline == other.offline && update == other.update;
}
}

}
Loading

0 comments on commit 42397c7

Please sign in to comment.