http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java new file mode 100644 index 0000000..e78df3a --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java @@ -0,0 +1,91 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A simple session data storage backed by a thread-safe map. + */ +public final class DefaultSessionData + implements SessionData +{ + + private final ConcurrentMap<Object, Object> data; + + public DefaultSessionData() + { + data = new ConcurrentHashMap<Object, Object>(); + } + + public void set( Object key, Object value ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + if ( value != null ) + { + data.put( key, value ); + } + else + { + data.remove( key ); + } + } + + public boolean set( Object key, Object oldValue, Object newValue ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + if ( newValue != null ) + { + if ( oldValue == null ) + { + return data.putIfAbsent( key, newValue ) == null; + } + return data.replace( key, oldValue, newValue ); + } + else + { + if ( oldValue == null ) + { + return !data.containsKey( key ); + } + return data.remove( key, oldValue ); + } + } + + public Object get( Object key ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + return data.get( key ); + } + +}
http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java new file mode 100644 index 0000000..6f9f114 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java @@ -0,0 +1,59 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Caches auxiliary data used during repository access like already processed metadata. The data in the cache is meant + * for exclusive consumption by the repository system and is opaque to the cache implementation. <strong>Note:</strong> + * Actual cache implementations must be thread-safe. + * + * @see RepositorySystemSession#getCache() + */ +public interface RepositoryCache +{ + + /** + * Puts the specified data into the cache. It is entirely up to the cache implementation how long this data will be + * kept before being purged, i.e. callers must not make any assumptions about the lifetime of cached data. + * <p> + * <em>Warning:</em> The cache will directly save the provided reference. If the cached data is mutable, i.e. could + * be modified after being put into the cache, the caller is responsible for creating a copy of the original data + * and store the copy in the cache. + * + * @param session The repository session during which the cache is accessed, must not be {@code null}. + * @param key The key to use for lookup of the data, must not be {@code null}. + * @param data The data to store in the cache, may be {@code null}. + */ + void put( RepositorySystemSession session, Object key, Object data ); + + /** + * Gets the specified data from the cache. + * <p> + * <em>Warning:</em> The cache will directly return the saved reference. If the cached data is to be modified after + * its retrieval, the caller is responsible to create a copy of the returned data and use this instead of the cache + * record. + * + * @param session The repository session during which the cache is accessed, must not be {@code null}. + * @param key The key to use for lookup of the data, must not be {@code null}. + * @return The requested data or {@code null} if none was present in the cache. + */ + Object get( RepositorySystemSession session, Object key ); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java new file mode 100644 index 0000000..33816ba --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java @@ -0,0 +1,442 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.ArtifactRepository; + +/** + * An event describing an action performed by the repository system. Note that events which indicate the end of an + * action like {@link EventType#ARTIFACT_RESOLVED} are generally fired in both the success and the failure case. Use + * {@link #getException()} to check whether an event denotes success or failure. + * + * @see RepositoryListener + * @see RepositoryEvent.Builder + */ +public final class RepositoryEvent +{ + + /** + * The type of the repository event. + */ + public enum EventType + { + + /** + * @see RepositoryListener#artifactDescriptorInvalid(RepositoryEvent) + */ + ARTIFACT_DESCRIPTOR_INVALID, + + /** + * @see RepositoryListener#artifactDescriptorMissing(RepositoryEvent) + */ + ARTIFACT_DESCRIPTOR_MISSING, + + /** + * @see RepositoryListener#metadataInvalid(RepositoryEvent) + */ + METADATA_INVALID, + + /** + * @see RepositoryListener#artifactResolving(RepositoryEvent) + */ + ARTIFACT_RESOLVING, + + /** + * @see RepositoryListener#artifactResolved(RepositoryEvent) + */ + ARTIFACT_RESOLVED, + + /** + * @see RepositoryListener#metadataResolving(RepositoryEvent) + */ + METADATA_RESOLVING, + + /** + * @see RepositoryListener#metadataResolved(RepositoryEvent) + */ + METADATA_RESOLVED, + + /** + * @see RepositoryListener#artifactDownloading(RepositoryEvent) + */ + ARTIFACT_DOWNLOADING, + + /** + * @see RepositoryListener#artifactDownloaded(RepositoryEvent) + */ + ARTIFACT_DOWNLOADED, + + /** + * @see RepositoryListener#metadataDownloading(RepositoryEvent) + */ + METADATA_DOWNLOADING, + + /** + * @see RepositoryListener#metadataDownloaded(RepositoryEvent) + */ + METADATA_DOWNLOADED, + + /** + * @see RepositoryListener#artifactInstalling(RepositoryEvent) + */ + ARTIFACT_INSTALLING, + + /** + * @see RepositoryListener#artifactInstalled(RepositoryEvent) + */ + ARTIFACT_INSTALLED, + + /** + * @see RepositoryListener#metadataInstalling(RepositoryEvent) + */ + METADATA_INSTALLING, + + /** + * @see RepositoryListener#metadataInstalled(RepositoryEvent) + */ + METADATA_INSTALLED, + + /** + * @see RepositoryListener#artifactDeploying(RepositoryEvent) + */ + ARTIFACT_DEPLOYING, + + /** + * @see RepositoryListener#artifactDeployed(RepositoryEvent) + */ + ARTIFACT_DEPLOYED, + + /** + * @see RepositoryListener#metadataDeploying(RepositoryEvent) + */ + METADATA_DEPLOYING, + + /** + * @see RepositoryListener#metadataDeployed(RepositoryEvent) + */ + METADATA_DEPLOYED + + } + + private final EventType type; + + private final RepositorySystemSession session; + + private final Artifact artifact; + + private final Metadata metadata; + + private final ArtifactRepository repository; + + private final File file; + + private final List<Exception> exceptions; + + private final RequestTrace trace; + + RepositoryEvent( Builder builder ) + { + type = builder.type; + session = builder.session; + artifact = builder.artifact; + metadata = builder.metadata; + repository = builder.repository; + file = builder.file; + exceptions = builder.exceptions; + trace = builder.trace; + } + + /** + * Gets the type of the event. + * + * @return The type of the event, never {@code null}. + */ + public EventType getType() + { + return type; + } + + /** + * Gets the repository system session during which the event occurred. + * + * @return The repository system session during which the event occurred, never {@code null}. + */ + public RepositorySystemSession getSession() + { + return session; + } + + /** + * Gets the artifact involved in the event (if any). + * + * @return The involved artifact or {@code null} if none. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Gets the metadata involved in the event (if any). + * + * @return The involved metadata or {@code null} if none. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Gets the file involved in the event (if any). + * + * @return The involved file or {@code null} if none. + */ + public File getFile() + { + return file; + } + + /** + * Gets the repository involved in the event (if any). + * + * @return The involved repository or {@code null} if none. + */ + public ArtifactRepository getRepository() + { + return repository; + } + + /** + * Gets the exception that caused the event (if any). As a rule of thumb, an event accompanied by an exception + * indicates a failure of the corresponding action. If multiple exceptions occurred, this method returns the first + * exception. + * + * @return The exception or {@code null} if none. + */ + public Exception getException() + { + return exceptions.isEmpty() ? null : exceptions.get( 0 ); + } + + /** + * Gets the exceptions that caused the event (if any). As a rule of thumb, an event accompanied by exceptions + * indicates a failure of the corresponding action. + * + * @return The exceptions, never {@code null}. + */ + public List<Exception> getExceptions() + { + return exceptions; + } + + /** + * Gets the trace information about the request during which the event occurred. + * + * @return The trace information or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( getType() ); + if ( getArtifact() != null ) + { + buffer.append( " " ).append( getArtifact() ); + } + if ( getMetadata() != null ) + { + buffer.append( " " ).append( getMetadata() ); + } + if ( getFile() != null ) + { + buffer.append( " (" ).append( getFile() ).append( ")" ); + } + if ( getRepository() != null ) + { + buffer.append( " @ " ).append( getRepository() ); + } + return buffer.toString(); + } + + /** + * A builder to create events. + */ + public static final class Builder + { + + EventType type; + + RepositorySystemSession session; + + Artifact artifact; + + Metadata metadata; + + ArtifactRepository repository; + + File file; + + List<Exception> exceptions = Collections.emptyList(); + + RequestTrace trace; + + /** + * Creates a new event builder for the specified session and event type. + * + * @param session The repository system session, must not be {@code null}. + * @param type The type of the event, must not be {@code null}. + */ + public Builder( RepositorySystemSession session, EventType type ) + { + if ( session == null ) + { + throw new IllegalArgumentException( "session not specified" ); + } + this.session = session; + if ( type == null ) + { + throw new IllegalArgumentException( "event type not specified" ); + } + this.type = type; + } + + /** + * Sets the artifact involved in the event. + * + * @param artifact The involved artifact, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Sets the metadata involved in the event. + * + * @param metadata The involved metadata, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Sets the repository involved in the event. + * + * @param repository The involved repository, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setRepository( ArtifactRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Sets the file involved in the event. + * + * @param file The involved file, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setFile( File file ) + { + this.file = file; + return this; + } + + /** + * Sets the exception causing the event. + * + * @param exception The exception causing the event, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setException( Exception exception ) + { + if ( exception != null ) + { + this.exceptions = Collections.singletonList( exception ); + } + else + { + this.exceptions = Collections.emptyList(); + } + return this; + } + + /** + * Sets the exceptions causing the event. + * + * @param exceptions The exceptions causing the event, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setExceptions( List<Exception> exceptions ) + { + if ( exceptions != null ) + { + this.exceptions = exceptions; + } + else + { + this.exceptions = Collections.emptyList(); + } + return this; + } + + /** + * Sets the trace information about the request during which the event occurred. + * + * @param trace The trace information, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + /** + * Builds a new event from the current values of this builder. The state of the builder itself remains + * unchanged. + * + * @return The event, never {@code null}. + */ + public RepositoryEvent build() + { + return new RepositoryEvent( this ); + } + + } + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java new file mode 100644 index 0000000..c2d1718 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java @@ -0,0 +1,69 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * The base class for exceptions thrown by the repository system. <em>Note:</em> Unless otherwise noted, instances of + * this class and its subclasses will not persist fields carrying extended error information during serialization. + */ +public class RepositoryException + extends Exception +{ + + /** + * Creates a new exception with the specified detail message. + * + * @param message The detail message, may be {@code null}. + */ + public RepositoryException( String message ) + { + super( message ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public RepositoryException( String message, Throwable cause ) + { + super( message, cause ); + } + + /** + * @noreference This method is not intended to be used by clients. + */ + protected static String getMessage( String prefix, Throwable cause ) + { + String msg = ""; + if ( cause != null ) + { + msg = cause.getMessage(); + if ( msg == null || msg.length() <= 0 ) + { + msg = cause.getClass().getSimpleName(); + } + msg = prefix + msg; + } + return msg; + } + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java new file mode 100644 index 0000000..d654630 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java @@ -0,0 +1,222 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A listener being notified of events from the repository system. In general, the system sends events upon termination + * of an operation like {@link #artifactResolved(RepositoryEvent)} regardless whether it succeeded or failed so + * listeners need to inspect the event details carefully. Also, the listener may be called from an arbitrary thread. + * <em>Note:</em> Implementors are strongly advised to inherit from {@link AbstractRepositoryListener} instead of + * directly implementing this interface. + * + * @see org.eclipse.aether.RepositorySystemSession#getRepositoryListener() + * @see org.eclipse.aether.transfer.TransferListener + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositoryListener +{ + + /** + * Notifies the listener of a syntactically or semantically invalid artifact descriptor. + * {@link RepositoryEvent#getArtifact()} indicates the artifact whose descriptor is invalid and + * {@link RepositoryEvent#getExceptions()} carries the encountered errors. Depending on the session's + * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort + * with an exception or ignore the invalid descriptor. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDescriptorInvalid( RepositoryEvent event ); + + /** + * Notifies the listener of a missing artifact descriptor. {@link RepositoryEvent#getArtifact()} indicates the + * artifact whose descriptor is missing. Depending on the session's + * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort + * with an exception or ignore the missing descriptor. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDescriptorMissing( RepositoryEvent event ); + + /** + * Notifies the listener of syntactically or semantically invalid metadata. {@link RepositoryEvent#getMetadata()} + * indicates the invalid metadata and {@link RepositoryEvent#getExceptions()} carries the encountered errors. The + * underlying repository operation might still succeed, depending on whether the metadata in question is actually + * needed to carry out the resolution process. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInvalid( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be resolved. {@link RepositoryEvent#getArtifact()} denotes + * the artifact in question. Unlike the {@link #artifactDownloading(RepositoryEvent)} event, this event is fired + * regardless whether the artifact already exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void artifactResolving( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose resolution has been completed, either successfully or not. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the + * {@link #artifactDownloaded(RepositoryEvent)} event, this event is fired regardless whether the artifact already + * exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void artifactResolved( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be resolved. {@link RepositoryEvent#getMetadata()} + * denotes the metadata in question. Unlike the {@link #metadataDownloading(RepositoryEvent)} event, this event is + * fired regardless whether the metadata already exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void metadataResolving( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose resolution has been completed, either successfully or not. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the + * {@link #metadataDownloaded(RepositoryEvent)} event, this event is fired regardless whether the metadata already + * exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void metadataResolved( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be downloaded from a remote repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getRepository()} the source repository. Unlike the + * {@link #artifactResolving(RepositoryEvent)} event, this event is only fired when the artifact does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDownloading( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose download has been completed, either successfully or not. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the + * {@link #artifactResolved(RepositoryEvent)} event, this event is only fired when the artifact does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDownloaded( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be downloaded from a remote repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getRepository()} the source repository. Unlike the + * {@link #metadataResolving(RepositoryEvent)} event, this event is only fired when the metadata does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDownloading( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose download has been completed, either successfully or not. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the + * {@link #metadataResolved(RepositoryEvent)} event, this event is only fired when the metadata does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDownloaded( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be installed to the local repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question. + * + * @param event The event details, must not be {@code null}. + */ + void artifactInstalling( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose installation to the local repository has been completed, either + * successfully or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void artifactInstalled( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be installed to the local repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInstalling( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose installation to the local repository has been completed, either + * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInstalled( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be uploaded to a remote repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getRepository()} the destination repository. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDeploying( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose upload to a remote repository has been completed, either successfully + * or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDeployed( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be uploaded to a remote repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getRepository()} the destination repository. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDeploying( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose upload to a remote repository has been completed, either + * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDeployed( RepositoryEvent event ); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java new file mode 100644 index 0000000..8706f89 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java @@ -0,0 +1,277 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Collection; +import java.util.List; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.CollectResult; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.deployment.DeployResult; +import org.eclipse.aether.deployment.DeploymentException; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.installation.InstallResult; +import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorException; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactDescriptorResult; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.resolution.DependencyResult; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.MetadataResult; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.resolution.VersionRequest; +import org.eclipse.aether.resolution.VersionResolutionException; +import org.eclipse.aether.resolution.VersionResult; + +/** + * The main entry point to the repository system and its functionality. Note that obtaining a concrete implementation of + * this interface (e.g. via dependency injection, service locator, etc.) is dependent on the application and its + * specific needs, please consult the online documentation for examples and directions on booting the system. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositorySystem +{ + + /** + * Expands a version range to a list of matching versions, in ascending order. For example, resolves "[3.8,4.0)" to + * "3.8", "3.8.1", "3.8.2". Note that the returned list of versions is only dependent on the configured repositories + * and their contents, the list is not processed by the {@link RepositorySystemSession#getVersionFilter() session's + * version filter}. + * <p> + * The supplied request may also refer to a single concrete version rather than a version range. In this case + * though, the result contains simply the (parsed) input version, regardless of the repositories and their contents. + * + * @param session The repository session, must not be {@code null}. + * @param request The version range request, must not be {@code null}. + * @return The version range result, never {@code null}. + * @throws VersionRangeResolutionException If the requested range could not be parsed. Note that an empty range does + * not raise an exception. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) + throws VersionRangeResolutionException; + + /** + * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" to + * "1.0-20090208.132618-23". + * + * @param session The repository session, must not be {@code null}. + * @param request The version request, must not be {@code null}. + * @return The version result, never {@code null}. + * @throws VersionResolutionException If the metaversion could not be resolved. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) + throws VersionResolutionException; + + /** + * Gets information about an artifact like its direct dependencies and potential relocations. + * + * @param session The repository session, must not be {@code null}. + * @param request The descriptor request, must not be {@code null}. + * @return The descriptor result, never {@code null}. + * @throws ArtifactDescriptorException If the artifact descriptor could not be read. + * @see RepositorySystemSession#getArtifactDescriptorPolicy() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) + throws ArtifactDescriptorException; + + /** + * Collects the transitive dependencies of an artifact and builds a dependency graph. Note that this operation is + * only concerned about determining the coordinates of the transitive dependencies. To also resolve the actual + * artifact files, use {@link #resolveDependencies(RepositorySystemSession, DependencyRequest)}. + * + * @param session The repository session, must not be {@code null}. + * @param request The collection request, must not be {@code null}. + * @return The collection result, never {@code null}. + * @throws DependencyCollectionException If the dependency tree could not be built. + * @see RepositorySystemSession#getDependencyTraverser() + * @see RepositorySystemSession#getDependencyManager() + * @see RepositorySystemSession#getDependencySelector() + * @see RepositorySystemSession#getVersionFilter() + * @see RepositorySystemSession#getDependencyGraphTransformer() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request ) + throws DependencyCollectionException; + + /** + * Collects and resolves the transitive dependencies of an artifact. This operation is essentially a combination of + * {@link #collectDependencies(RepositorySystemSession, CollectRequest)} and + * {@link #resolveArtifacts(RepositorySystemSession, Collection)}. + * + * @param session The repository session, must not be {@code null}. + * @param request The dependency request, must not be {@code null}. + * @return The dependency result, never {@code null}. + * @throws DependencyResolutionException If the dependency tree could not be built or any dependency artifact could + * not be resolved. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + DependencyResult resolveDependencies( RepositorySystemSession session, DependencyRequest request ) + throws DependencyResolutionException; + + /** + * Resolves the path for an artifact. The artifact will be downloaded to the local repository if necessary. An + * artifact that is already resolved will be skipped and is not re-resolved. In general, callers must not assume any + * relationship between an artifact's resolved filename and its coordinates. Note that this method assumes that any + * relocations have already been processed. + * + * @param session The repository session, must not be {@code null}. + * @param request The resolution request, must not be {@code null}. + * @return The resolution result, never {@code null}. + * @throws ArtifactResolutionException If the artifact could not be resolved. + * @see Artifact#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request ) + throws ArtifactResolutionException; + + /** + * Resolves the paths for a collection of artifacts. Artifacts will be downloaded to the local repository if + * necessary. Artifacts that are already resolved will be skipped and are not re-resolved. In general, callers must + * not assume any relationship between an artifact's filename and its coordinates. Note that this method assumes + * that any relocations have already been processed. + * + * @param session The repository session, must not be {@code null}. + * @param requests The resolution requests, must not be {@code null}. + * @return The resolution results (in request order), never {@code null}. + * @throws ArtifactResolutionException If any artifact could not be resolved. + * @see Artifact#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + List<ArtifactResult> resolveArtifacts( RepositorySystemSession session, + Collection<? extends ArtifactRequest> requests ) + throws ArtifactResolutionException; + + /** + * Resolves the paths for a collection of metadata. Metadata will be downloaded to the local repository if + * necessary, e.g. because it hasn't been cached yet or the cache is deemed outdated. + * + * @param session The repository session, must not be {@code null}. + * @param requests The resolution requests, must not be {@code null}. + * @return The resolution results (in request order), never {@code null}. + * @see Metadata#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + List<MetadataResult> resolveMetadata( RepositorySystemSession session, + Collection<? extends MetadataRequest> requests ); + + /** + * Installs a collection of artifacts and their accompanying metadata to the local repository. + * + * @param session The repository session, must not be {@code null}. + * @param request The installation request, must not be {@code null}. + * @return The installation result, never {@code null}. + * @throws InstallationException If any artifact/metadata from the request could not be installed. + */ + InstallResult install( RepositorySystemSession session, InstallRequest request ) + throws InstallationException; + + /** + * Uploads a collection of artifacts and their accompanying metadata to a remote repository. + * + * @param session The repository session, must not be {@code null}. + * @param request The deployment request, must not be {@code null}. + * @return The deployment result, never {@code null}. + * @throws DeploymentException If any artifact/metadata from the request could not be deployed. + * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) + */ + DeployResult deploy( RepositorySystemSession session, DeployRequest request ) + throws DeploymentException; + + /** + * Creates a new manager for the specified local repository. If the specified local repository has no type, the + * default local repository type of the system will be used. <em>Note:</em> It is expected that this method + * invocation is one of the last steps of setting up a new session, in particular any configuration properties + * should have been set already. + * + * @param session The repository system session from which to configure the manager, must not be {@code null}. + * @param localRepository The local repository to create a manager for, must not be {@code null}. + * @return The local repository manager, never {@code null}. + * @throws IllegalArgumentException If the specified repository type is not recognized or no base directory is + * given. + */ + LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository localRepository ); + + /** + * Creates a new synchronization context. + * + * @param session The repository session during which the context will be used, must not be {@code null}. + * @param shared A flag indicating whether access to the artifacts/metadata associated with the new context can be + * shared among concurrent readers or whether access needs to be exclusive to the calling thread. + * @return The synchronization context, never {@code null}. + */ + SyncContext newSyncContext( RepositorySystemSession session, boolean shared ); + + /** + * Forms remote repositories suitable for artifact resolution by applying the session's authentication selector and + * similar network configuration to the given repository prototypes. As noted for + * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the remote repositories passed to e.g. + * {@link #resolveArtifact(RepositorySystemSession, ArtifactRequest) resolveArtifact()} are used as is and expected + * to already carry any required authentication or proxy configuration. This method can be used to apply the + * authentication/proxy configuration from a session to a bare repository definition to obtain the complete + * repository definition for use in the resolution request. + * + * @param session The repository system session from which to configure the repositories, must not be {@code null}. + * @param repositories The repository prototypes from which to derive the resolution repositories, must not be + * {@code null} or contain {@code null} elements. + * @return The resolution repositories, never {@code null}. Note that there is generally no 1:1 relationship of the + * obtained repositories to the original inputs due to mirror selection potentially aggregating multiple + * repositories. + * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) + */ + List<RemoteRepository> newResolutionRepositories( RepositorySystemSession session, + List<RemoteRepository> repositories ); + + /** + * Forms a remote repository suitable for artifact deployment by applying the session's authentication selector and + * similar network configuration to the given repository prototype. As noted for + * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the remote repository passed to + * {@link #deploy(RepositorySystemSession, DeployRequest) deploy()} is used as is and expected to already carry any + * required authentication or proxy configuration. This method can be used to apply the authentication/proxy + * configuration from a session to a bare repository definition to obtain the complete repository definition for use + * in the deploy request. + * + * @param session The repository system session from which to configure the repository, must not be {@code null}. + * @param repository The repository prototype from which to derive the deployment repository, must not be + * {@code null}. + * @return The deployment repository, never {@code null}. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + RemoteRepository newDeploymentRepository( RepositorySystemSession session, RemoteRepository repository ); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java new file mode 100644 index 0000000..888f29c --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java @@ -0,0 +1,263 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; + +/** + * Defines settings and components that control the repository system. Once initialized, the session object itself is + * supposed to be immutable and hence can safely be shared across an entire application and any concurrent threads + * reading it. Components that wish to tweak some aspects of an existing session should use the copy constructor of + * {@link DefaultRepositorySystemSession} and its mutators to derive a custom session. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositorySystemSession +{ + + /** + * Indicates whether the repository system operates in offline mode and avoids/refuses any access to remote + * repositories. + * + * @return {@code true} if the repository system is in offline mode, {@code false} otherwise. + */ + boolean isOffline(); + + /** + * Indicates whether repositories declared in artifact descriptors should be ignored during transitive dependency + * collection. If enabled, only the repositories originally provided with the collect request will be considered. + * + * @return {@code true} if additional repositories from artifact descriptors are ignored, {@code false} to merge + * those with the originally specified repositories. + */ + boolean isIgnoreArtifactDescriptorRepositories(); + + /** + * Gets the policy which controls whether resolutions errors from remote repositories should be cached. + * + * @return The resolution error policy for this session or {@code null} if resolution errors should generally not be + * cached. + */ + ResolutionErrorPolicy getResolutionErrorPolicy(); + + /** + * Gets the policy which controls how errors related to reading artifact descriptors should be handled. + * + * @return The descriptor error policy for this session or {@code null} if descriptor errors should generally not be + * tolerated. + */ + ArtifactDescriptorPolicy getArtifactDescriptorPolicy(); + + /** + * Gets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote + * repositories being used for resolution. + * + * @return The global checksum policy or {@code null}/empty if not set and the per-repository policies apply. + * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL + * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE + * @see RepositoryPolicy#CHECKSUM_POLICY_WARN + */ + String getChecksumPolicy(); + + /** + * Gets the global update policy. If set, the global update policy overrides the update policies of the remote + * repositories being used for resolution. + * + * @return The global update policy or {@code null}/empty if not set and the per-repository policies apply. + * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS + * @see RepositoryPolicy#UPDATE_POLICY_DAILY + * @see RepositoryPolicy#UPDATE_POLICY_NEVER + */ + String getUpdatePolicy(); + + /** + * Gets the local repository used during this session. This is a convenience method for + * {@link LocalRepositoryManager#getRepository()}. + * + * @return The local repository being during this session, never {@code null}. + */ + LocalRepository getLocalRepository(); + + /** + * Gets the local repository manager used during this session. + * + * @return The local repository manager used during this session, never {@code null}. + */ + LocalRepositoryManager getLocalRepositoryManager(); + + /** + * Gets the workspace reader used during this session. If set, the workspace reader will usually be consulted first + * to resolve artifacts. + * + * @return The workspace reader for this session or {@code null} if none. + */ + WorkspaceReader getWorkspaceReader(); + + /** + * Gets the listener being notified of actions in the repository system. + * + * @return The repository listener or {@code null} if none. + */ + RepositoryListener getRepositoryListener(); + + /** + * Gets the listener being notified of uploads/downloads by the repository system. + * + * @return The transfer listener or {@code null} if none. + */ + TransferListener getTransferListener(); + + /** + * Gets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually + * collected from the runtime environment like {@link System#getProperties()} and environment variables. + * + * @return The (read-only) system properties, never {@code null}. + */ + Map<String, String> getSystemProperties(); + + /** + * Gets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to + * system properties but are set on the discretion of the user and hence are considered of higher priority than + * system properties. + * + * @return The (read-only) user properties, never {@code null}. + */ + Map<String, String> getUserProperties(); + + /** + * Gets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling, + * connector-specific behavior, etc.) + * + * @return The (read-only) configuration properties, never {@code null}. + * @see ConfigurationProperties + */ + Map<String, Object> getConfigProperties(); + + /** + * Gets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to denote the effective repositories. + * + * @return The mirror selector to use, never {@code null}. + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + MirrorSelector getMirrorSelector(); + + /** + * Gets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to have their proxy (if any) already set. + * + * @return The proxy selector to use, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getProxy() + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + ProxySelector getProxySelector(); + + /** + * Gets the authentication selector to use for repositories discovered in artifact descriptors. Note that this + * selector is not used for remote repositories which are passed as request parameters to the repository system, + * those repositories are supposed to have their authentication (if any) already set. + * + * @return The authentication selector to use, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication() + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + AuthenticationSelector getAuthenticationSelector(); + + /** + * Gets the registry of artifact types recognized by this session, for instance when processing artifact + * descriptors. + * + * @return The artifact type registry, never {@code null}. + */ + ArtifactTypeRegistry getArtifactTypeRegistry(); + + /** + * Gets the dependency traverser to use for building dependency graphs. + * + * @return The dependency traverser to use for building dependency graphs or {@code null} if dependencies are + * unconditionally traversed. + */ + DependencyTraverser getDependencyTraverser(); + + /** + * Gets the dependency manager to use for building dependency graphs. + * + * @return The dependency manager to use for building dependency graphs or {@code null} if dependency management is + * not performed. + */ + DependencyManager getDependencyManager(); + + /** + * Gets the dependency selector to use for building dependency graphs. + * + * @return The dependency selector to use for building dependency graphs or {@code null} if dependencies are + * unconditionally included. + */ + DependencySelector getDependencySelector(); + + /** + * Gets the version filter to use for building dependency graphs. + * + * @return The version filter to use for building dependency graphs or {@code null} if versions aren't filtered. + */ + VersionFilter getVersionFilter(); + + /** + * Gets the dependency graph transformer to use for building dependency graphs. + * + * @return The dependency graph transformer to use for building dependency graphs or {@code null} if none. + */ + DependencyGraphTransformer getDependencyGraphTransformer(); + + /** + * Gets the custom data associated with this session. + * + * @return The session data, never {@code null}. + */ + SessionData getData(); + + /** + * Gets the cache the repository system may use to save data for future reuse during the session. + * + * @return The repository cache or {@code null} if none. + */ + RepositoryCache getCache(); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java new file mode 100644 index 0000000..86aaa78 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java @@ -0,0 +1,117 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A trace of nested requests that are performed by the repository system. This trace information can be used to + * correlate repository events with higher level operations in the application code that eventually caused the events. A + * single trace can carry an arbitrary object as data which is meant to describe a request/operation that is currently + * executed. For call hierarchies within the repository system itself, this data will usually be the {@code *Request} + * object that is currently processed. When invoking methods on the repository system, client code may provide a request + * trace that has been prepopulated with whatever data is useful for the application to indicate its state for later + * evaluation when processing the repository events. + * + * @see RepositoryEvent#getTrace() + */ +public class RequestTrace +{ + + private final RequestTrace parent; + + private final Object data; + + /** + * Creates a child of the specified request trace. This method is basically a convenience that will invoke + * {@link RequestTrace#newChild(Object) parent.newChild()} when the specified parent trace is not {@code null} or + * otherwise instantiante a new root trace. + * + * @param parent The parent request trace, may be {@code null}. + * @param data The data to associate with the child trace, may be {@code null}. + * @return The child trace, never {@code null}. + */ + public static RequestTrace newChild( RequestTrace parent, Object data ) + { + if ( parent == null ) + { + return new RequestTrace( data ); + } + return parent.newChild( data ); + } + + /** + * Creates a new root trace with the specified data. + * + * @param data The data to associate with the trace, may be {@code null}. + */ + public RequestTrace( Object data ) + { + this( null, data ); + } + + /** + * Creates a new trace with the specified data and parent + * + * @param parent The parent trace, may be {@code null} for a root trace. + * @param data The data to associate with the trace, may be {@code null}. + */ + protected RequestTrace( RequestTrace parent, Object data ) + { + this.parent = parent; + this.data = data; + } + + /** + * Gets the data associated with this trace. + * + * @return The data associated with this trace or {@code null} if none. + */ + public final Object getData() + { + return data; + } + + /** + * Gets the parent of this trace. + * + * @return The parent of this trace or {@code null} if this is the root of the trace stack. + */ + public final RequestTrace getParent() + { + return parent; + } + + /** + * Creates a new child of this trace. + * + * @param data The data to associate with the child, may be {@code null}. + * @return The child trace, never {@code null}. + */ + public RequestTrace newChild( Object data ) + { + return new RequestTrace( this, data ); + } + + @Override + public String toString() + { + return String.valueOf( getData() ); + } + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java b/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java new file mode 100644 index 0000000..b6efeac --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java @@ -0,0 +1,66 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A container for data that is specific to a repository system session. Both components within the repository system + * and clients of the system may use this storage to associate arbitrary data with a session. + * <p> + * Unlike a cache, this session data is not subject to purging. For this same reason, session data should also not be + * abused as a cache (i.e. for storing values that can be re-calculated) to avoid memory exhaustion. + * <p> + * <strong>Note:</strong> Actual implementations must be thread-safe. + * + * @see RepositorySystemSession#getData() + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface SessionData +{ + + /** + * Associates the specified session data with the given key. + * + * @param key The key under which to store the session data, must not be {@code null}. + * @param value The data to associate with the key, may be {@code null} to remove the mapping. + */ + void set( Object key, Object value ); + + /** + * Associates the specified session data with the given key if the key is currently mapped to the given value. This + * method provides an atomic compare-and-update of some key's value. + * + * @param key The key under which to store the session data, must not be {@code null}. + * @param oldValue The expected data currently associated with the key, may be {@code null}. + * @param newValue The data to associate with the key, may be {@code null} to remove the mapping. + * @return {@code true} if the key mapping was successfully updated from the old value to the new value, + * {@code false} if the current key mapping didn't match the expected value and was not updated. + */ + boolean set( Object key, Object oldValue, Object newValue ); + + /** + * Gets the session data associated with the specified key. + * + * @param key The key for which to retrieve the session data, must not be {@code null}. + * @return The session data associated with the key or {@code null} if none. + */ + Object get( Object key ); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java new file mode 100644 index 0000000..2d751c0 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java @@ -0,0 +1,76 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.Closeable; +import java.util.Collection; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * A synchronization context used to coordinate concurrent access to artifacts or metadatas. The typical usage of a + * synchronization context looks like this: + * + * <pre> + * SyncContext syncContext = repositorySystem.newSyncContext( ... ); + * try { + * syncContext.acquire( artifacts, metadatas ); + * // work with the artifacts and metadatas + * } finally { + * syncContext.close(); + * } + * </pre> + * + * Within one thread, synchronization contexts may be nested which can naturally happen in a hierarchy of method calls. + * The nested synchronization contexts may also acquire overlapping sets of artifacts/metadatas as long as the following + * conditions are met. If the outer-most context holding a particular resource is exclusive, that resource can be + * reacquired in any nested context. If however the outer-most context is shared, the resource may only be reacquired by + * nested contexts if these are also shared. + * <p> + * A synchronization context is meant to be utilized by only one thread and as such is not thread-safe. + * <p> + * Note that the level of actual synchronization is subject to the implementation and might range from OS-wide to none. + * + * @see RepositorySystem#newSyncContext(RepositorySystemSession, boolean) + */ +public interface SyncContext + extends Closeable +{ + + /** + * Acquires synchronized access to the specified artifacts and metadatas. The invocation will potentially block + * until all requested resources can be acquired by the calling thread. Acquiring resources that are already + * acquired by this synchronization context has no effect. Please also see the class-level documentation for + * information regarding reentrancy. The method may be invoked multiple times on a synchronization context until all + * desired resources have been acquired. + * + * @param artifacts The artifacts to acquire, may be {@code null} or empty if none. + * @param metadatas The metadatas to acquire, may be {@code null} or empty if none. + */ + void acquire( Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas ); + + /** + * Releases all previously acquired artifacts/metadatas. If no resources have been acquired before or if this + * synchronization context has already been closed, this method does nothing. + */ + void close(); + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java new file mode 100644 index 0000000..d89260b --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java @@ -0,0 +1,230 @@ +package org.eclipse.aether.artifact; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A skeleton class for artifacts. + */ +public abstract class AbstractArtifact + implements Artifact +{ + + private static final String SNAPSHOT = "SNAPSHOT"; + + private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile( "^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$" ); + + public boolean isSnapshot() + { + return isSnapshot( getVersion() ); + } + + private static boolean isSnapshot( String version ) + { + return version.endsWith( SNAPSHOT ) || SNAPSHOT_TIMESTAMP.matcher( version ).matches(); + } + + public String getBaseVersion() + { + return toBaseVersion( getVersion() ); + } + + private static String toBaseVersion( String version ) + { + String baseVersion; + + if ( version == null ) + { + baseVersion = version; + } + else if ( version.startsWith( "[" ) || version.startsWith( "(" ) ) + { + baseVersion = version; + } + else + { + Matcher m = SNAPSHOT_TIMESTAMP.matcher( version ); + if ( m.matches() ) + { + if ( m.group( 1 ) != null ) + { + baseVersion = m.group( 1 ) + SNAPSHOT; + } + else + { + baseVersion = SNAPSHOT; + } + } + else + { + baseVersion = version; + } + } + + return baseVersion; + } + + /** + * Creates a new artifact with the specified coordinates, properties and file. + * + * @param version The version of the artifact, may be {@code null}. + * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability + * of the supplied map, i.e. need not copy it. + * @param file The resolved file of the artifact, may be {@code null}. + * @return The new artifact instance, never {@code null}. + */ + private Artifact newInstance( String version, Map<String, String> properties, File file ) + { + return new DefaultArtifact( getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, file, + properties ); + } + + public Artifact setVersion( String version ) + { + String current = getVersion(); + if ( current.equals( version ) || ( version == null && current.length() <= 0 ) ) + { + return this; + } + return newInstance( version, getProperties(), getFile() ); + } + + public Artifact setFile( File file ) + { + File current = getFile(); + if ( ( current == null ) ? file == null : current.equals( file ) ) + { + return this; + } + return newInstance( getVersion(), getProperties(), file ); + } + + public Artifact setProperties( Map<String, String> properties ) + { + Map<String, String> current = getProperties(); + if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) ) + { + return this; + } + return newInstance( getVersion(), copyProperties( properties ), getFile() ); + } + + public String getProperty( String key, String defaultValue ) + { + String value = getProperties().get( key ); + return ( value != null ) ? value : defaultValue; + } + + /** + * Copies the specified artifact properties. This utility method should be used when creating new artifact instances + * with caller-supplied properties. + * + * @param properties The properties to copy, may be {@code null}. + * @return The copied and read-only properties, never {@code null}. + */ + protected static Map<String, String> copyProperties( Map<String, String> properties ) + { + if ( properties != null && !properties.isEmpty() ) + { + return Collections.unmodifiableMap( new HashMap<String, String>( properties ) ); + } + else + { + return Collections.emptyMap(); + } + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 128 ); + buffer.append( getGroupId() ); + buffer.append( ':' ).append( getArtifactId() ); + buffer.append( ':' ).append( getExtension() ); + if ( getClassifier().length() > 0 ) + { + buffer.append( ':' ).append( getClassifier() ); + } + buffer.append( ':' ).append( getVersion() ); + return buffer.toString(); + } + + /** + * Compares this artifact with the specified object. + * + * @param obj The object to compare this artifact against, may be {@code null}. + * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates, + * properties and file, {@code false} otherwise. + */ + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( !( obj instanceof Artifact ) ) + { + return false; + } + + Artifact that = (Artifact) obj; + + return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() ) + && getVersion().equals( that.getVersion() ) && getExtension().equals( that.getExtension() ) + && getClassifier().equals( that.getClassifier() ) && eq( getFile(), that.getFile() ) + && getProperties().equals( that.getProperties() ); + } + + private static <T> boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + /** + * Returns a hash code for this artifact. + * + * @return A hash code for the artifact. + */ + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + getGroupId().hashCode(); + hash = hash * 31 + getArtifactId().hashCode(); + hash = hash * 31 + getExtension().hashCode(); + hash = hash * 31 + getClassifier().hashCode(); + hash = hash * 31 + getVersion().hashCode(); + hash = hash * 31 + hash( getFile() ); + return hash; + } + + private static int hash( Object obj ) + { + return ( obj != null ) ? obj.hashCode() : 0; + } + +} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java ---------------------------------------------------------------------- diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java new file mode 100644 index 0000000..6323243 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java @@ -0,0 +1,143 @@ +package org.eclipse.aether.artifact; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.Map; + +/** + * A specific artifact. In a nutshell, an artifact has identifying coordinates and optionally a file that denotes its + * data. <em>Note:</em> Artifact instances are supposed to be immutable, e.g. any exposed mutator method returns a new + * artifact instance and leaves the original instance unchanged. <em>Note:</em> Implementors are strongly advised to + * inherit from {@link AbstractArtifact} instead of directly implementing this interface. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface Artifact +{ + + /** + * Gets the group identifier of this artifact, for example "org.apache.maven". + * + * @return The group identifier, never {@code null}. + */ + String getGroupId(); + + /** + * Gets the artifact identifier of this artifact, for example "maven-model". + * + * @return The artifact identifier, never {@code null}. + */ + String getArtifactId(); + + /** + * Gets the version of this artifact, for example "1.0-20100529-1213". Note that in case of meta versions like + * "1.0-SNAPSHOT", the artifact's version depends on the state of the artifact. Artifacts that have been resolved or + * deployed will usually have the meta version expanded. + * + * @return The version, never {@code null}. + */ + String getVersion(); + + /** + * Sets the version of the artifact. + * + * @param version The version of this artifact, may be {@code null} or empty. + * @return The new artifact, never {@code null}. + */ + Artifact setVersion( String version ); + + /** + * Gets the base version of this artifact, for example "1.0-SNAPSHOT". In contrast to the {@link #getVersion()}, the + * base version will always refer to the unresolved meta version. + * + * @return The base version, never {@code null}. + */ + String getBaseVersion(); + + /** + * Determines whether this artifact uses a snapshot version. + * + * @return {@code true} if the artifact is a snapshot, {@code false} otherwise. + */ + boolean isSnapshot(); + + /** + * Gets the classifier of this artifact, for example "sources". + * + * @return The classifier or an empty string if none, never {@code null}. + */ + String getClassifier(); + + /** + * Gets the (file) extension of this artifact, for example "jar" or "tar.gz". + * + * @return The file extension (without leading period), never {@code null}. + */ + String getExtension(); + + /** + * Gets the file of this artifact. Note that only resolved artifacts have a file associated with them. In general, + * callers must not assume any relationship between an artifact's filename and its coordinates. + * + * @return The file or {@code null} if the artifact isn't resolved. + */ + File getFile(); + + /** + * Sets the file of the artifact. + * + * @param file The file of the artifact, may be {@code null} + * @return The new artifact, never {@code null}. + */ + Artifact setFile( File file ); + + /** + * Gets the specified property. + * + * @param key The name of the property, must not be {@code null}. + * @param defaultValue The default value to return in case the property is not set, may be {@code null}. + * @return The requested property value or {@code null} if the property is not set and no default value was + * provided. + * @see ArtifactProperties + */ + String getProperty( String key, String defaultValue ); + + /** + * Gets the properties of this artifact. Clients may use these properties to associate non-persistent values with an + * artifact that help later processing when the artifact gets passed around within the application. + * + * @return The (read-only) properties, never {@code null}. + * @see ArtifactProperties + */ + Map<String, String> getProperties(); + + /** + * Sets the properties for the artifact. Note that these properties exist merely in memory and are not persisted + * when the artifact gets installed/deployed to a repository. + * + * @param properties The properties for the artifact, may be {@code null}. + * @return The new artifact, never {@code null}. + * @see ArtifactProperties + */ + Artifact setProperties( Map<String, String> properties ); + +}