Skip to content

Commit

Permalink
Add an ArtifactManager to allows unified managing of artifacts
Browse files Browse the repository at this point in the history
Caching can greatly improve performance, basically P2 has two concepts
of where caching can occur, the transport and artifacts that can
originate from different sources. Currently there is only a CacheManger
for handling the first case and nothing for the second, maybe even more
important case. Because of this there are different approaches out in
the wild e.g. PDE Bundle Pools, Oomph shared P2 pools, and Tycho is
using its own cache in the m2 repository, but all of them suffer from
the fact that there is no real convenient entry point so different
things needs to be enhanced an managed.

This now adds a new abstraction service the ArtifactManager that allows
to intercept the process of downloading a logical artifact from a given
location and possibly providing an equivalent one that is already
present locally. There is also a default implementation that simply
delegates to the transport directly as before,
  • Loading branch information
laeubi committed Jan 5, 2025
1 parent 4837102 commit bb6ee1c
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dsVersion=V1_4
eclipse.preferences.version=1
enabled=true
generateBundleActivationPolicyLazy=true
path=OSGI-INF
validationErrorLevel=error
validationErrorLevel.missingImplicitUnbindMethod=error
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ Import-Package: javax.xml.parsers,
org.osgi.service.prefs;version="1.1.1",
org.w3c.dom,
org.xml.sax;resolution:=optional
Service-Component: OSGI-INF/repositoryManager.xml
Service-Component: OSGI-INF/org.eclipse.equinox.internal.p2.artifact.repository.DefaultArtifactManagerServiceFactory.xml,
OSGI-INF/repositoryManager.xml
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17
Automatic-Module-Name: org.eclipse.equinox.p2.artifact.repository
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/org.eclipse.equinox.*.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2025 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.equinox.internal.p2.artifact.repository;

import java.io.OutputStream;
import java.net.URI;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.equinox.internal.p2.repository.DownloadStatus;
import org.eclipse.equinox.internal.provisional.p2.repository.IStateful;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.osgi.annotation.versioning.ProviderType;

/**
* The artifact manager is responsible for managing artifacts on a per agent
* basis. It possibly caches the data from previous requests to improve
* performance or knows alternative locations to fetch the artifacts.
*/
@ProviderType
public interface ArtifactManager {

/**
* Service name for the artifact manager service.
*/
String SERVICE_NAME = "org.eclipse.equinox.internal.p2.repository.ArtifactManager"; //$NON-NLS-1$

/**
* Acquire the artifact described by the given artifact descriptor and writing
* it into the target output stream. Progress is reported on the monitor. If the
* <code>target</code> is an instance of {@link IStateful} the resulting status
* is also reported on the target.
*
* @return IStatus that is a {@link DownloadStatus} if the artifact was
* downloaded from a remote server, or a plain status in other cases
* (including errors).
* @param source An URI of file to download from a remote, this might be a
* mirror of the actual artifact repository
* @param target the {@link OutputStream} where result is written
* @param descriptor the descriptor of the artifact that is about to be
* downloaded
* @param monitor where progress should be reported, might be
* <code>null</code> if no progress reporting is desired
*/
IStatus getArtifact(URI source, OutputStream target, IArtifactDescriptor descriptor, IProgressMonitor monitor);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2025 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.equinox.internal.p2.artifact.repository;

import java.io.OutputStream;
import java.net.URI;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.repository.Transport;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.spi.AgentServicename;
import org.eclipse.equinox.p2.core.spi.IAgentServiceFactory;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.osgi.service.component.annotations.Component;

/**
* The default implementation of a {@link ArtifactManager} simply delegates to
* the transport.
*/
@Component(service = IAgentServiceFactory.class)
@AgentServicename(ArtifactManager.class)
public class DefaultArtifactManagerServiceFactory implements IAgentServiceFactory {

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

private static final class DefaultArtifactManager implements ArtifactManager {
private IProvisioningAgent agent;

public DefaultArtifactManager(IProvisioningAgent agent) {
this.agent = agent;
}

@Override
public IStatus getArtifact(URI source, OutputStream target, IArtifactDescriptor descriptor,
IProgressMonitor monitor) {
Transport transport = agent.getService(Transport.class);
if (transport == null) {
return Status.CANCEL_STATUS;
}
return transport.downloadArtifact(source, target, descriptor, monitor);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ private IStatus downloadArtifact(IArtifactDescriptor descriptor, URI mirrorLocat
if (SimpleArtifactRepositoryFactory.PROTOCOL_FILE.equals(mirrorLocation.getScheme()))
result = copyFileToStream(new File(mirrorLocation), destination, monitor);
else
result = getTransport().downloadArtifact(mirrorLocation, destination, descriptor, monitor);
result = getArtifactManger().getArtifact(mirrorLocation, destination, descriptor, monitor);
if (mirrors != null)
mirrors.reportResult(mirrorLocation.toString(), result);
if (result.isOK() || result.getSeverity() == IStatus.CANCEL)
Expand Down Expand Up @@ -1142,6 +1142,10 @@ private Transport getTransport() {
return getProvisioningAgent().getService(Transport.class);
}

private ArtifactManager getArtifactManger() {
return getProvisioningAgent().getService(ArtifactManager.class);
}

// use this method to setup any transient fields etc after the object has been restored from a stream
public synchronized void initializeAfterLoad(URI repoLocation) {
this.initializeAfterLoad(repoLocation, true);
Expand Down

0 comments on commit bb6ee1c

Please sign in to comment.