scopes()
+ {
+ return scopes;
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java
new file mode 100644
index 0000000000..f246e9fd7f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java
@@ -0,0 +1,57 @@
+package org.apache.maven.api;
+
+/*
+ * 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.Locale;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Scope for a dependency
+ *
+ * @since 4.0
+ */
+@Experimental
+public enum Scope
+{
+ COMPILE( "compile" ),
+ PROVIDED ( "provided" ),
+ SYSTEM( "system" ),
+ RUNTIME( "runtime" ),
+ TEST( "test" ),
+ IMPORT( "import" );
+
+ private final String id;
+
+ Scope( String id )
+ {
+ this.id = id;
+ }
+
+ public String id()
+ {
+ return this.id;
+ }
+
+ public static Scope get( String scope )
+ {
+ return Enum.valueOf( Scope.class, scope.toUpperCase( Locale.ROOT ) );
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java
new file mode 100644
index 0000000000..a4cabcaa7b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java
@@ -0,0 +1,37 @@
+package org.apache.maven.api;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+/**
+ * Marker interface for all services provided by the {@link Session}.
+ *
+ * Services can be retrieved from the session using the
+ * {@link Session#getService(Class)} method.
+ *
+ * @see Session#getService(Class)
+ */
+@Experimental
+@ThreadSafe
+public interface Service
+{
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
new file mode 100644
index 0000000000..0d0cf07f9c
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
@@ -0,0 +1,346 @@
+package org.apache.maven.api;
+
+/*
+ * 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.nio.file.Path;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Properties;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.ThreadSafe;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.services.DependencyCoordinateFactory;
+import org.apache.maven.api.settings.Settings;
+
+/**
+ * The session to install / deploy / resolve artifacts and dependencies.
+ *
+ * @since 4.0
+ */
+@Experimental
+@ThreadSafe
+public interface Session
+{
+
+ @Nonnull
+ Settings getSettings();
+
+ @Nonnull
+ LocalRepository getLocalRepository();
+
+ @Nonnull
+ List getRemoteRepositories();
+
+ @Nonnull
+ SessionData getData();
+
+ // TODO: investigate using Map or Map for all properties in the new API
+ @Nonnull
+ Properties getUserProperties();
+
+ @Nonnull
+ Properties getSystemProperties();
+
+ /**
+ * Returns the current maven version
+ * @return the maven version, never {@code null}.
+ */
+ @Nonnull
+ String getMavenVersion();
+
+ int getDegreeOfConcurrency();
+
+ @Nonnull
+ Instant getStartTime();
+
+ @Nonnull
+ Path getMultiModuleProjectDirectory();
+
+ @Nonnull
+ Path getExecutionRootDirectory();
+
+ @Nonnull
+ List getProjects();
+
+ /**
+ * Returns the plugin context for mojo being executed and the specified
+ * {@link Project}, never returns {@code null} as if context not present, creates it.
+ *
+ * Implementation note: while this method return type is {@link Map}, the returned map instance
+ * implements {@link java.util.concurrent.ConcurrentMap} as well.
+ *
+ * @throws org.apache.maven.api.services.MavenException if not called from the within a mojo execution
+ */
+ @Nonnull
+ Map getPluginContext( @Nonnull Project project );
+
+ /**
+ * Retrieves the service for the interface
+ *
+ * @throws NoSuchElementException if the service could not be found
+ */
+ @Nonnull
+ T getService( @Nonnull Class clazz );
+
+ /**
+ * Creates a derived session using the given local repository.
+ *
+ * @param localRepository the new local repository
+ * @return the derived session
+ * @throws NullPointerException if {@code localRepository} is null
+ */
+ @Nonnull
+ Session withLocalRepository( @Nonnull LocalRepository localRepository );
+
+ /**
+ * Creates a derived session using the given remote repositories.
+ *
+ * @param repositories the new list of remote repositories
+ * @return the derived session
+ * @throws NullPointerException if {@code repositories} is null
+ */
+ @Nonnull
+ Session withRemoteRepositories( @Nonnull List repositories );
+
+ /**
+ * Register the given listener which will receive all events.
+ *
+ * @param listener the listener to register
+ * @throws NullPointerException if {@code listener} is null
+ */
+ void registerListener( @Nonnull Listener listener );
+
+ /**
+ * Unregisters a previously registered listener.
+ *
+ * @param listener the listener to unregister
+ * @throws NullPointerException if {@code listener} is null
+ */
+ void unregisterListener( @Nonnull Listener listener );
+
+ /**
+ * Returns the list of registered listeners.
+ *
+ * @return an immutable collection of listeners, never {@code null}
+ */
+ @Nonnull
+ Collection getListeners();
+
+ /**
+ * Shortcut for getService(RepositoryFactory.class).createLocal(...)
+ * @see org.apache.maven.api.services.RepositoryFactory#createLocal(Path)
+ */
+ LocalRepository createLocalRepository( Path path );
+
+ /**
+ * Shortcut for getService(RepositoryFactory.class).createRemote(...)
+ * @see org.apache.maven.api.services.RepositoryFactory#createRemote(String, String)
+ */
+ @Nonnull
+ RemoteRepository createRemoteRepository( @Nonnull String id, @Nonnull String url );
+
+ /**
+ * Shortcut for getService(RepositoryFactory.class).createRemote(...)
+ * @see org.apache.maven.api.services.RepositoryFactory#createRemote(Repository)
+ */
+ @Nonnull
+ RemoteRepository createRemoteRepository( @Nonnull Repository repository );
+
+ /**
+ * Shortcut for getService(ArtifactFactory.class).create(...)
+ * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
+ */
+ ArtifactCoordinate createArtifactCoordinate( String groupId, String artifactId, String version, String extension );
+
+ /**
+ * Shortcut for getService(ArtifactFactory.class).create(...)
+ * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+ */
+ ArtifactCoordinate createArtifactCoordinate( String groupId, String artifactId, String version, String classifier,
+ String extension, String type );
+
+ /**
+ * Shortcut for getService(ArtifactFactory.class).create(...)
+ * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+ */
+ ArtifactCoordinate createArtifactCoordinate( Artifact artifact );
+
+ /**
+ * Shortcut for getService(DependencyFactory.class).create(...)
+ * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
+ */
+ @Nonnull
+ DependencyCoordinate createDependencyCoordinate( @Nonnull ArtifactCoordinate coordinate );
+
+ /**
+ * Shortcut for getService(ArtifactFactory.class).create(...)
+ * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
+ */
+ Artifact createArtifact( String groupId, String artifactId, String version, String extension );
+
+ /**
+ * Shortcut for getService(ArtifactFactory.class).create(...)
+ * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+ */
+ Artifact createArtifact( String groupId, String artifactId, String version, String classifier,
+ String extension, String type );
+
+ /**
+ * Shortcut for getService(ArtifactResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+ */
+ Artifact resolveArtifact( ArtifactCoordinate coordinate );
+
+ /**
+ * Shortcut for getService(ArtifactResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+ */
+ Collection resolveArtifacts( ArtifactCoordinate... coordinates );
+
+ /**
+ * Shortcut for getService(ArtifactResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+ */
+ Collection resolveArtifacts( Collection extends ArtifactCoordinate> coordinates );
+
+ /**
+ * Shortcut for getService(ArtifactResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+ */
+ Artifact resolveArtifact( Artifact artifact );
+
+ /**
+ * Shortcut for getService(ArtifactResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+ */
+ Collection resolveArtifacts( Artifact... artifacts );
+
+ /**
+ * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+ * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
+ */
+ void installArtifacts( Artifact... artifacts );
+
+ /**
+ * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+ * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
+ */
+ void installArtifacts( Collection artifacts );
+
+ /**
+ * Shortcut for getService(ArtifactDeployer.class).deploy(...)
+ * @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
+ *
+ * @throws org.apache.maven.api.services.ArtifactDeployerException if the artifacts deployment failed
+ */
+ void deployArtifact( RemoteRepository repository, Artifact... artifacts );
+
+ /**
+ * Shortcut for getService(ArtifactManager.class).setPath(...)
+ * @see org.apache.maven.api.services.ArtifactManager#setPath(Artifact, Path)
+ */
+ void setArtifactPath( @Nonnull Artifact artifact, @Nonnull Path path );
+
+ /**
+ * Shortcut for getService(ArtifactManager.class).getPath(...)
+ * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
+ */
+ @Nonnull
+ Optional getArtifactPath( @Nonnull Artifact artifact );
+
+ /**
+ * Shortcut for getService(ArtifactManager.class).isSnapshot(...)
+ * @see org.apache.maven.api.services.VersionParser#isSnapshot(String)
+ */
+ boolean isVersionSnapshot( @Nonnull String version );
+
+ /**
+ * Shortcut for getService(DependencyCollector.class).collect(...)
+ * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact)
+ *
+ * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+ */
+ @Nonnull
+ Node collectDependencies( @Nonnull Artifact artifact );
+
+ /**
+ * Shortcut for getService(DependencyCollector.class).collect(...)
+ * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project)
+ *
+ * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+ */
+ @Nonnull
+ Node collectDependencies( @Nonnull Project project );
+
+ /**
+ * Shortcut for getService(DependencyResolver.class).resolve(...)
+ * @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate)
+ *
+ * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+ */
+ @Nonnull
+ Node collectDependencies( @Nonnull DependencyCoordinate dependency );
+
+ Path getPathForLocalArtifact( @Nonnull Artifact artifact );
+
+ Path getPathForLocalMetadata( Metadata metadata );
+
+ Path getPathForRemoteArtifact( RemoteRepository remote, Artifact artifact );
+
+ Path getPathForRemoteMetadata( RemoteRepository remote, Metadata metadata );
+
+ /**
+ * Shortcut for getService(VersionParser.class).parseVersion(...)
+ * @see org.apache.maven.api.services.VersionParser#parseVersion(String)
+ *
+ * @throws org.apache.maven.api.services.VersionParserException if the parsing failed
+ */
+ @Nonnull
+ Version parseVersion( @Nonnull String version );
+
+ /**
+ * Shortcut for getService(VersionParser.class).parseVersionRange(...)
+ * @see org.apache.maven.api.services.VersionParser#parseVersionRange(String)
+ *
+ * @throws org.apache.maven.api.services.VersionParserException if the parsing failed
+ */
+ @Nonnull
+ VersionRange parseVersionRange( @Nonnull String versionRange );
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java b/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java
new file mode 100644
index 0000000000..8a8ef19401
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java
@@ -0,0 +1,86 @@
+package org.apache.maven.api;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.annotations.Provider;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+import java.util.function.Supplier;
+
+/**
+ * A container for data that is specific to a session.
+ * All components may use this storage to associate arbitrary data with a session.
+ *
+ * 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.
+ *
+ * Note: Actual implementations must be thread-safe.
+ *
+ * @see Session#getData()
+ * @since 4.0
+ */
+@Experimental
+@ThreadSafe @Provider
+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( @Nonnull Object key, @Nullable 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( @Nonnull Object key, @Nullable Object oldValue, @Nullable 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.
+ */
+ @Nullable
+ Object get( @Nonnull Object key );
+
+ /**
+ * Retrieve of compute the data associated with the specified key.
+ *
+ * @param key The key for which to retrieve the session data, must not be {@code null}.
+ * @param supplier The supplier will compute the new value.
+ * @return The session data associated with the key.
+ */
+ @Nullable
+ Object computeIfAbsent( @Nonnull Object key, @Nonnull Supplier supplier );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
new file mode 100644
index 0000000000..2f497194e3
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
@@ -0,0 +1,56 @@
+package org.apache.maven.api;
+
+/*
+ * 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.apache.maven.api.annotations.Experimental;
+
+/**
+ * Toolchain interface.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface Toolchain
+{
+ /**
+ * get the type of toolchain.
+ *
+ * @return the toolchain type
+ */
+ String getType();
+
+ /**
+ * Gets the platform tool executable.
+ *
+ * @param toolName the tool platform independent tool name.
+ * @return file representing the tool executable, or null if the tool can not be found
+ */
+ String findTool( String toolName );
+
+ /**
+ * Let the toolchain decide if it matches requirements defined
+ * in the toolchain plugin configuration.
+ * @param requirements Map<String, String> key value pair, may not be {@code null}
+ * @return {@code true} if the requirements match, otherwise {@code false}
+ */
+ boolean matchesRequirements( Map requirements );
+}
\ No newline at end of file
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
new file mode 100644
index 0000000000..71a94b2e28
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
@@ -0,0 +1,72 @@
+package org.apache.maven.api;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+
+/**
+ * An artifact's{@code Type} represents a known kind of artifacts.
+ * Such types are often associated to an extension and possibly
+ * a classifier, for example {@code java-source} has a {@code jar}
+ * extension and a {@code sources} classifier.
+ * It is also used to determine if a given dependency should be
+ * included in the classpath or if its transitive dependencies should.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface Type
+{
+
+ String POM = "pom";
+ String JAR = "jar";
+ String JAVA_SOURCE = "java-source";
+ String JAVADOC = "javadoc";
+ String MAVEN_PLUGIN = "maven-plugin";
+ String TEST_JAR = "test-jar";
+
+ /**
+ * Returns the dependency type name.
+ *
+ * @return the type name
+ */
+ String getName();
+
+ /**
+ * Get the file extension associated to the file represented by the dependency type.
+ *
+ * @return the file extension
+ */
+ String getExtension();
+
+ /**
+ * Get the classifier associated to the dependency type.
+ *
+ * @return the classifier
+ */
+ String getClassifier();
+
+ boolean isIncludesDependencies();
+
+ boolean isAddedToClasspath();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java
new file mode 100644
index 0000000000..bf75f6c1d2
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java
@@ -0,0 +1,46 @@
+package org.apache.maven.api;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A version usually parsed using the {@link org.apache.maven.api.services.VersionParser} service.
+ *
+ * @since 4.0
+ * @see org.apache.maven.api.services.VersionParser#parseVersion(String)
+ * @see org.apache.maven.api.Session#parseVersion(String)
+ */
+@Experimental
+public interface Version
+ extends Comparable
+{
+
+ // TODO: add access to the version information
+
+ /**
+ * Returns a string representation of this version.
+ * @return the string representation of this version
+ */
+ @Nonnull
+ String asString();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java
new file mode 100644
index 0000000000..fb3e39b2f6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java
@@ -0,0 +1,50 @@
+package org.apache.maven.api;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A range of versions.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface VersionRange
+{
+
+ // TODO: add access to the version information
+
+ /**
+ * Determines whether the specified version is contained within this range.
+ *
+ * @param version The version to test, must not be {@code null}.
+ * @return {@code true} if this range contains the specified version, {@code false} otherwise.
+ */
+ boolean contains( @Nonnull Version version );
+
+ /**
+ * Returns a string representation of this version range
+ * @return the string representation of this version range
+ */
+ @Nonnull
+ String asString();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
new file mode 100644
index 0000000000..f0eb2a660a
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
@@ -0,0 +1,168 @@
+package org.apache.maven.api.plugin;
+
+/*
+ * 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.function.Supplier;
+
+/**
+ * This interface supplies the API for providing feedback to the user from the Mojo
, using standard
+ * Maven
channels.
+ * There should be no big surprises here, although you may notice that the methods accept
+ * java.lang.CharSequence
rather than java.lang.String
. This is provided mainly as a
+ * convenience, to enable developers to pass things like java.lang.StringBuffer
directly into the logger,
+ * rather than formatting first by calling toString()
.
+ *
+ * @since 4.0
+ */
+public interface Log
+{
+ /**
+ * @return true if the debug error level is enabled
+ */
+ boolean isDebugEnabled();
+
+ /**
+ * Send a message to the user in the debug error level.
+ *
+ * @param content
+ */
+ void debug( CharSequence content );
+
+ /**
+ * Send a message (and accompanying exception) to the user in the debug error level.
+ * The error's stacktrace will be output when this error level is enabled.
+ *
+ * @param content
+ * @param error
+ */
+ void debug( CharSequence content, Throwable error );
+
+ /**
+ * Send an exception to the user in the debug error level.
+ * The stack trace for this exception will be output when this error level is enabled.
+ *
+ * @param error
+ */
+ void debug( Throwable error );
+
+ void debug( Supplier content );
+
+ void debug( Supplier content, Throwable error );
+
+ /**
+ * @return true if the info error level is enabled
+ */
+ boolean isInfoEnabled();
+
+ /**
+ * Send a message to the user in the info error level.
+ *
+ * @param content
+ */
+ void info( CharSequence content );
+
+ /**
+ * Send a message (and accompanying exception) to the user in the info error level.
+ * The error's stacktrace will be output when this error level is enabled.
+ *
+ * @param content
+ * @param error
+ */
+ void info( CharSequence content, Throwable error );
+
+ /**
+ * Send an exception to the user in the info error level.
+ * The stack trace for this exception will be output when this error level is enabled.
+ *
+ * @param error
+ */
+ void info( Throwable error );
+
+ void info( Supplier content );
+
+ void info( Supplier content, Throwable error );
+
+ /**
+ * @return true if the warn error level is enabled
+ */
+ boolean isWarnEnabled();
+
+ /**
+ * Send a message to the user in the warn error level.
+ *
+ * @param content
+ */
+ void warn( CharSequence content );
+
+ /**
+ * Send a message (and accompanying exception) to the user in the warn error level.
+ * The error's stacktrace will be output when this error level is enabled.
+ *
+ * @param content
+ * @param error
+ */
+ void warn( CharSequence content, Throwable error );
+
+ /**
+ * Send an exception to the user in the warn error level.
+ * The stack trace for this exception will be output when this error level is enabled.
+ *
+ * @param error
+ */
+ void warn( Throwable error );
+
+ void warn( Supplier content );
+
+ void warn( Supplier content, Throwable error );
+
+ /**
+ * @return true if the error error level is enabled
+ */
+ boolean isErrorEnabled();
+
+ /**
+ * Send a message to the user in the error error level.
+ *
+ * @param content
+ */
+ void error( CharSequence content );
+
+ /**
+ * Send a message (and accompanying exception) to the user in the error error level.
+ * The error's stacktrace will be output when this error level is enabled.
+ *
+ * @param content
+ * @param error
+ */
+ void error( CharSequence content, Throwable error );
+
+ /**
+ * Send an exception to the user in the error error level.
+ * The stack trace for this exception will be output when this error level is enabled.
+ *
+ * @param error
+ */
+ void error( Throwable error );
+
+ void error( Supplier content );
+
+ void error( Supplier content, Throwable error );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
new file mode 100644
index 0000000000..a6217bff2a
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
@@ -0,0 +1,46 @@
+package org.apache.maven.api.plugin;
+
+/*
+ * 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 org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * This interface forms the contract required for Mojos
to interact with the Maven
+ * infrastructure.
+ * It features an execute()
method, which triggers the Mojo's build-process behavior, and can throw
+ * a MojoException if error conditions occur.
+ *
+ * @since 4.0
+ */
+@Experimental
+@FunctionalInterface @Consumer
+public interface Mojo
+{
+ /**
+ * Perform whatever build-process behavior this Mojo
implements.
+ * This is the main trigger for the Mojo
inside the Maven
system, and allows
+ * the Mojo
to communicate errors.
+ *
+ * @throws MojoException if a problem occurs.
+ */
+ void execute();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
new file mode 100644
index 0000000000..5e5b0c7eee
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
@@ -0,0 +1,98 @@
+package org.apache.maven.api.plugin;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception occurring during the execution of a plugin.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class MojoException
+ extends MavenException
+{
+
+ protected Object source;
+
+ protected String longMessage;
+
+ /**
+ * Construct a new MojoExecutionException
exception providing the source and a short and long message:
+ * these messages are used to improve the message written at the end of Maven build.
+ */
+ public MojoException( Object source, String shortMessage, String longMessage )
+ {
+ super( shortMessage );
+ this.source = source;
+ this.longMessage = longMessage;
+ }
+
+ /**
+ * Construct a new MojoExecutionException
exception wrapping an underlying Exception
+ * and providing a message
.
+ */
+ public MojoException( String message, Exception cause )
+ {
+ super( message, cause );
+ }
+
+ /**
+ * Construct a new MojoExecutionException
exception wrapping an underlying Throwable
+ * and providing a message
.
+ */
+ public MojoException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+ /**
+ * Construct a new MojoExecutionException
exception providing a message
.
+ */
+ public MojoException( String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Constructs a new {@code MojoExecutionException} exception wrapping an underlying {@code Throwable}.
+ *
+ * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method.
+ * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
+ * @since 3.8.3
+ */
+ public MojoException( Throwable cause )
+ {
+ super( cause );
+ }
+
+ public String getLongMessage()
+ {
+ return longMessage;
+ }
+
+ public Object getSource()
+ {
+ return source;
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Component.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Component.java
new file mode 100644
index 0000000000..f963dfa98c
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Component.java
@@ -0,0 +1,56 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Used to configure injection of Plexus components by
+ *
+ * MavenPluginManager.getConfiguredMojo(...)
.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER } )
+@Inherited
+public @interface Component
+{
+ /**
+ * role of the component to inject.
+ * @return the role
+ */
+ Class> role() default Object.class;
+
+ /**
+ * hint of the component to inject.
+ * @return the hint
+ */
+ String hint() default "";
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java
new file mode 100644
index 0000000000..e4f870786a
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java
@@ -0,0 +1,64 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Used if your Mojo needs to fork a lifecycle .
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( ElementType.TYPE )
+@Inherited
+public @interface Execute
+{
+ /**
+ * lifecycle phase to fork. Note that specifying a phase overrides specifying a goal.
+ * @return the phase
+ */
+ LifecyclePhase phase() default LifecyclePhase.NONE;
+
+ /**
+ * goal to fork. Note that specifying a phase overrides specifying a goal. The specified goal
must be
+ * another goal of the same plugin.
+ * @return the goal
+ */
+ String goal() default "";
+
+ /**
+ * lifecycle id of the lifecycle that defines {@link #phase()}. Only valid in combination with {@link #phase()}. If
+ * not specified, Maven will use the lifecycle of the current build.
+ *
+ * @see Lifecycle Mappings
+ * @return the lifecycle id
+ */
+ String lifecycle() default "";
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/InstantiationStrategy.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/InstantiationStrategy.java
new file mode 100644
index 0000000000..c5cfc75ec6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/InstantiationStrategy.java
@@ -0,0 +1,48 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Component instantiation strategy.
+ *
+ * @since 4.0
+ */
+@Experimental
+public enum InstantiationStrategy
+{
+ PER_LOOKUP( "per-lookup" ),
+ SINGLETON( "singleton" ),
+ KEEP_ALIVE( "keep-alive" ),
+ POOLABLE( "poolable" );
+
+ private final String id;
+
+ InstantiationStrategy( String id )
+ {
+ this.id = id;
+ }
+
+ public String id()
+ {
+ return this.id;
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java
new file mode 100644
index 0000000000..84c567b4dc
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java
@@ -0,0 +1,80 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Lifecycle phases .
+ *
+ * @since 4.0
+ */
+@Experimental
+public enum LifecyclePhase
+{
+
+ VALIDATE( "validate" ),
+ INITIALIZE( "initialize" ),
+ GENERATE_SOURCES( "generate-sources" ),
+ PROCESS_SOURCES( "process-sources" ),
+ GENERATE_RESOURCES( "generate-resources" ),
+ PROCESS_RESOURCES( "process-resources" ),
+ COMPILE( "compile" ),
+ PROCESS_CLASSES( "process-classes" ),
+ GENERATE_TEST_SOURCES( "generate-test-sources" ),
+ PROCESS_TEST_SOURCES( "process-test-sources" ),
+ GENERATE_TEST_RESOURCES( "generate-test-resources" ),
+ PROCESS_TEST_RESOURCES( "process-test-resources" ),
+ TEST_COMPILE( "test-compile" ),
+ PROCESS_TEST_CLASSES( "process-test-classes" ),
+ TEST( "test" ),
+ PREPARE_PACKAGE( "prepare-package" ),
+ PACKAGE( "package" ),
+ PRE_INTEGRATION_TEST( "pre-integration-test" ),
+ INTEGRATION_TEST( "integration-test" ),
+ POST_INTEGRATION_TEST( "post-integration-test" ),
+ VERIFY( "verify" ),
+ INSTALL( "install" ),
+ DEPLOY( "deploy" ),
+
+ PRE_CLEAN( "pre-clean" ),
+ CLEAN( "clean" ),
+ POST_CLEAN( "post-clean" ),
+
+ PRE_SITE( "pre-site" ),
+ SITE( "site" ),
+ POST_SITE( "post-site" ),
+ SITE_DEPLOY( "site-deploy" ),
+
+ NONE( "" );
+
+ private final String id;
+
+ LifecyclePhase( String id )
+ {
+ this.id = id;
+ }
+
+ public String id()
+ {
+ return this.id;
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java
new file mode 100644
index 0000000000..e87341140d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java
@@ -0,0 +1,98 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.ResolutionScope;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * This annotation will mark your class as a Mojo (ie. goal in a Maven plugin).
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( ElementType.TYPE )
+@Inherited
+public @interface Mojo
+{
+ /**
+ * goal name (required).
+ * @return the goal name
+ */
+ String name();
+
+ /**
+ * default phase to bind your mojo.
+ * @return the default phase
+ */
+ LifecyclePhase defaultPhase() default LifecyclePhase.NONE;
+
+ /**
+ * the required dependency resolution scope.
+ * @return the required dependency resolution scope
+ */
+ ResolutionScope requiresDependencyResolution() default ResolutionScope.NONE;
+
+ /**
+ * the required dependency collection scope.
+ * @return the required dependency collection scope
+ */
+ ResolutionScope requiresDependencyCollection() default ResolutionScope.NONE;
+
+ /**
+ * your Mojo instantiation strategy. (Only per-lookup
and singleton
are supported)
+ * @return the instantiation strategy
+ */
+ InstantiationStrategy instantiationStrategy() default InstantiationStrategy.PER_LOOKUP;
+
+ /**
+ * does your mojo requires a project to be executed?
+ * @return requires a project
+ */
+ boolean requiresProject() default true;
+
+ /**
+ * if the Mojo uses the Maven project and its child modules.
+ * @return uses the Maven project and its child modules
+ */
+ boolean aggregator() default false;
+
+ /**
+ * does this Mojo need to be online to be executed?
+ * @return need to be online
+ */
+ boolean requiresOnline() default false;
+
+ /**
+ * configurator bean name.
+ * @return the configurator bean name
+ */
+ String configurator() default "";
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java
new file mode 100644
index 0000000000..27ada3d2a6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java
@@ -0,0 +1,94 @@
+package org.apache.maven.api.plugin.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Used to configure your Mojo parameters to be injected by
+ *
+ * MavenPluginManager.getConfiguredMojo(...)
.
+ *
+ * Beans injected into Mojo parameters are prepared by Sisu JSR330-based
+ * container: this annotation is only effective on fields of the Mojo class itself, nested bean injection
+ * requires Sisu or JSR330 annotations.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( { ElementType.FIELD, ElementType.METHOD } )
+@Inherited
+public @interface Parameter
+{
+ /**
+ * name of the bean property used to get/set the field: by default, field name is used.
+ * @return the name of the bean property
+ */
+ String name() default "";
+
+ /**
+ * alias supported to get parameter value.
+ * @return the alias
+ */
+ String alias() default "";
+
+ /**
+ * Property to use to retrieve a value. Can come from -D
execution, setting properties or pom
+ * properties.
+ * @return property name
+ */
+ String property() default "";
+
+ /**
+ * parameter default value, may contain ${...}
expressions which will be interpreted at
+ * inject time: see
+ *
+ * PluginParameterExpressionEvaluator .
+ * @return the default value
+ */
+ String defaultValue() default "";
+
+ /**
+ * is the parameter required?
+ * @return true
if the Mojo should fail when the parameter cannot be injected
+ */
+ boolean required() default false;
+
+ /**
+ * Specifies that this parameter cannot be configured directly by the user (as in the case of POM-specified
+ * configuration). This is useful when you want to force the user to use common POM elements rather than plugin
+ * configurations, as in the case where you want to use the artifact's final name as a parameter. In this case, you
+ * want the user to modify <build><finalName/></build>
rather than specifying a value
+ * for finalName directly in the plugin configuration section. It is also useful to ensure that - for example - a
+ * List-typed parameter which expects items of type Artifact doesn't get a List full of Strings.
+ *
+ * @return true
if the user should not be allowed to configure the parameter directly
+ */
+ boolean readonly() default false;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java
new file mode 100644
index 0000000000..a1da37134d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java
@@ -0,0 +1,71 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service used to create {@link ArtifactCoordinate} objects.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ArtifactCoordinateFactory extends Service
+{
+
+ /**
+ * Creates a coordinate.
+ *
+ * @param request the request holding coordinate creation parameters
+ * @return an {@code Artifact}, never {@code null}
+ * @throws IllegalArgumentException if {@code request} is null or {@code request.session} is null or invalid
+ */
+ @Nonnull
+ ArtifactCoordinate create( @Nonnull ArtifactCoordinateFactoryRequest request );
+
+ @Nonnull
+ default ArtifactCoordinate create( @Nonnull Session session, String groupId,
+ String artifactId, String version, String extension )
+ {
+ return create( ArtifactCoordinateFactoryRequest.build( session, groupId, artifactId, version, extension ) );
+ }
+
+ @Nonnull
+ default ArtifactCoordinate create( @Nonnull Session session, String groupId, String artifactId, String version,
+ String classifier, String extension, String type )
+ {
+ return create( ArtifactCoordinateFactoryRequest.build( session, groupId, artifactId,
+ version, classifier, extension, type ) );
+ }
+
+ @Nonnull
+ default ArtifactCoordinate create( @Nonnull Session session, Artifact artifact )
+ {
+ return create( ArtifactCoordinateFactoryRequest.build( session,
+ artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion().asString(),
+ artifact.getClassifier(), artifact.getExtension(), null ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java
new file mode 100644
index 0000000000..8c8b9af06f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java
@@ -0,0 +1,222 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+/**
+ * A request for creating a {@link ArtifactCoordinate} object.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactCoordinateFactoryRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ String getGroupId();
+
+ String getArtifactId();
+
+ String getVersion();
+
+ String getClassifier();
+
+ String getExtension();
+
+ String getType();
+
+ static ArtifactCoordinateFactoryRequest build( Session session, String groupId, String artifactId,
+ String version, String extension )
+ {
+ return ArtifactCoordinateFactoryRequest.builder()
+ .session( session )
+ .groupId( groupId )
+ .artifactId( artifactId )
+ .version( version )
+ .extension( extension )
+ .build();
+ }
+
+ static ArtifactCoordinateFactoryRequest build( Session session, String groupId, String artifactId,
+ String version, String classifier, String extension, String type )
+ {
+ return ArtifactCoordinateFactoryRequest.builder()
+ .session( session )
+ .groupId( groupId )
+ .artifactId( artifactId )
+ .version( version )
+ .classifier( classifier )
+ .extension( extension )
+ .type( type )
+ .build();
+ }
+
+ static ArtifactCoordinateFactoryRequest build( Session session, ArtifactCoordinate coordinate )
+ {
+ return ArtifactCoordinateFactoryRequest.builder()
+ .session( session )
+ .groupId( coordinate.getGroupId() )
+ .artifactId( coordinate.getArtifactId() )
+ .classifier( coordinate.getClassifier() )
+ .version( coordinate.getVersion().asString() )
+ .extension( coordinate.getExtension() )
+ .build();
+ }
+
+
+ static ArtifactFactoryRequestBuilder builder()
+ {
+ return new ArtifactFactoryRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class ArtifactFactoryRequestBuilder
+ {
+ private Session session;
+ private String groupId;
+ private String artifactId;
+ private String version;
+ private String classifier;
+ private String extension;
+ private String type;
+
+ public ArtifactFactoryRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder groupId( String groupId )
+ {
+ this.groupId = groupId;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder artifactId( String artifactId )
+ {
+ this.artifactId = artifactId;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder version( String version )
+ {
+ this.version = version;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder classifier( String classifier )
+ {
+ this.classifier = classifier;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder extension( String extension )
+ {
+ this.extension = extension;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder type( String type )
+ {
+ this.type = type;
+ return this;
+ }
+
+ public ArtifactCoordinateFactoryRequest build()
+ {
+ return new DefaultArtifactFactoryRequestArtifact( session, groupId, artifactId, version,
+ classifier, extension, type );
+ }
+
+ private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest implements
+ ArtifactCoordinateFactoryRequest
+ {
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String classifier;
+ private final String extension;
+ private final String type;
+
+ DefaultArtifactFactoryRequestArtifact( @Nonnull Session session,
+ String groupId,
+ String artifactId,
+ String version,
+ String classifier,
+ String extension,
+ String type )
+ {
+ super( session );
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ this.classifier = classifier;
+ this.extension = extension;
+ this.type = type;
+ }
+
+ @Override
+ public String getGroupId()
+ {
+ return groupId;
+ }
+
+ @Override
+ public String getArtifactId()
+ {
+ return artifactId;
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return version;
+ }
+
+ @Override
+ public String getClassifier()
+ {
+ return classifier;
+ }
+
+ @Override
+ public String getExtension()
+ {
+ return extension;
+ }
+
+ @Override
+ public String getType()
+ {
+ return type;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java
new file mode 100644
index 0000000000..38c243dbea
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java
@@ -0,0 +1,61 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Deploys {@link Artifact}s to a {@link RemoteRepository}.
+ *
+ * @since 4.0
+ * @see Session#deployArtifact(RemoteRepository, Artifact...)
+ */
+@Experimental
+public interface ArtifactDeployer extends Service
+{
+
+ /**
+ * @param request {@link ArtifactDeployerRequest}
+ * @throws ArtifactDeployerException if the deployment failed
+ */
+ void deploy( @Nonnull ArtifactDeployerRequest request );
+
+ /**
+ * @param session the repository session
+ * @param repository the repository to deploy to
+ * @param artifacts the collection of artifacts to deploy
+ * @throws ArtifactDeployerException if the deployment failed
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ */
+ default void deploy( @Nonnull Session session,
+ @Nonnull RemoteRepository repository,
+ @Nonnull Collection artifacts )
+ {
+ deploy( ArtifactDeployerRequest.build( session, repository, artifacts ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java
new file mode 100644
index 0000000000..fbb206a534
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java
@@ -0,0 +1,48 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * An artifact could not correctly being deployed.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class ArtifactDeployerException
+ extends MavenException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7421964724059077698L;
+
+ /**
+ * @param message The message of the error.
+ * @param e {@link Exception}
+ */
+ public ArtifactDeployerException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
new file mode 100644
index 0000000000..a87c0fbfc9
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
@@ -0,0 +1,153 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.util.Collection;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.RemoteRepository;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request for deploying one or more artifacts to a remote repository.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactDeployerRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ @Nonnull
+ RemoteRepository getRepository();
+
+ @Nonnull
+ Collection getArtifacts();
+
+ int getRetryFailedDeploymentCount();
+
+ @Nonnull
+ static ArtifactDeployerRequestBuilder builder()
+ {
+ return new ArtifactDeployerRequestBuilder();
+ }
+
+ @Nonnull
+ static ArtifactDeployerRequest build( @Nonnull Session session,
+ @Nonnull RemoteRepository repository,
+ @Nonnull Collection artifacts )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .repository( repository )
+ .artifacts( artifacts )
+ .build();
+ }
+
+ class ArtifactDeployerRequestBuilder
+ {
+ Session session;
+ RemoteRepository repository;
+ Collection artifacts;
+ int retryFailedDeploymentCount;
+
+ @Nonnull
+ public ArtifactDeployerRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactDeployerRequestBuilder repository( RemoteRepository repository )
+ {
+ this.repository = repository;
+ return this;
+ }
+
+ public ArtifactDeployerRequestBuilder artifacts( Collection artifacts )
+ {
+ this.artifacts = artifacts;
+ return this;
+ }
+
+ public ArtifactDeployerRequestBuilder retryFailedDeploymentCount( int retryFailedDeploymentCount )
+ {
+ this.retryFailedDeploymentCount = retryFailedDeploymentCount;
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactDeployerRequest build()
+ {
+ return new DefaultArtifactDeployerRequest( session, repository, artifacts, retryFailedDeploymentCount );
+ }
+
+ private static class DefaultArtifactDeployerRequest extends BaseRequest
+ implements ArtifactDeployerRequest
+ {
+
+ private final RemoteRepository repository;
+ private final Collection artifacts;
+ private final int retryFailedDeploymentCount;
+
+ DefaultArtifactDeployerRequest( @Nonnull Session session,
+ @Nonnull RemoteRepository repository,
+ @Nonnull Collection artifacts,
+ int retryFailedDeploymentCount )
+ {
+ super( session );
+ this.repository = nonNull( repository, "repository can not be null" );
+ this.artifacts = nonNull( artifacts, "artifacts can not be null" );
+ this.retryFailedDeploymentCount = retryFailedDeploymentCount;
+ }
+
+ @Nonnull
+ @Override
+ public RemoteRepository getRepository()
+ {
+ return repository;
+ }
+
+ @Nonnull
+ @Override
+ public Collection getArtifacts()
+ {
+ return artifacts;
+ }
+
+ @Override
+ public int getRetryFailedDeploymentCount()
+ {
+ return retryFailedDeploymentCount;
+ }
+ }
+
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java
new file mode 100644
index 0000000000..c9f2095aa0
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java
@@ -0,0 +1,61 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service used to create {@link Artifact} objects.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ArtifactFactory extends Service
+{
+
+ /**
+ * Creates an artifact.
+ *
+ * @param request the request holding artifact creation parameters
+ * @return an {@code Artifact}, never {@code null}
+ * @throws IllegalArgumentException if {@code request} is null or {@code request.session} is null or invalid
+ */
+ @Nonnull
+ Artifact create( @Nonnull ArtifactFactoryRequest request );
+
+ @Nonnull
+ default Artifact create( @Nonnull Session session, String groupId,
+ String artifactId, String version, String extension )
+ {
+ return create( ArtifactFactoryRequest.build( session, groupId, artifactId, version, extension ) );
+ }
+
+ @Nonnull
+ default Artifact create( @Nonnull Session session, String groupId, String artifactId, String version,
+ String classifier, String extension, String type )
+ {
+ return create( ArtifactFactoryRequest.build( session, groupId, artifactId,
+ version, classifier, extension, type ) );
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
new file mode 100644
index 0000000000..eb7e3f96cc
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
@@ -0,0 +1,208 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+/**
+ *
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactFactoryRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ String getGroupId();
+
+ String getArtifactId();
+
+ String getVersion();
+
+ String getClassifier();
+
+ String getExtension();
+
+ String getType();
+
+ static ArtifactFactoryRequest build( Session session, String groupId, String artifactId,
+ String version, String extension )
+ {
+ return ArtifactFactoryRequest.builder()
+ .session( session )
+ .groupId( groupId )
+ .artifactId( artifactId )
+ .version( version )
+ .extension( extension )
+ .build();
+ }
+
+ static ArtifactFactoryRequest build( Session session, String groupId, String artifactId,
+ String version, String classifier, String extension, String type )
+ {
+ return ArtifactFactoryRequest.builder()
+ .session( session )
+ .groupId( groupId )
+ .artifactId( artifactId )
+ .version( version )
+ .classifier( classifier )
+ .extension( extension )
+ .type( type )
+ .build();
+ }
+
+ static ArtifactFactoryRequestBuilder builder()
+ {
+ return new ArtifactFactoryRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class ArtifactFactoryRequestBuilder
+ {
+ private Session session;
+ private String groupId;
+ private String artifactId;
+ private String version;
+ private String classifier;
+ private String extension;
+ private String type;
+
+ public ArtifactFactoryRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder groupId( String groupId )
+ {
+ this.groupId = groupId;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder artifactId( String artifactId )
+ {
+ this.artifactId = artifactId;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder version( String version )
+ {
+ this.version = version;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder classifier( String classifier )
+ {
+ this.classifier = classifier;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder extension( String extension )
+ {
+ this.extension = extension;
+ return this;
+ }
+
+ public ArtifactFactoryRequestBuilder type( String type )
+ {
+ this.type = type;
+ return this;
+ }
+
+ public ArtifactFactoryRequest build()
+ {
+ return new DefaultArtifactFactoryRequest( session, groupId, artifactId, version,
+ classifier, extension, type );
+ }
+
+ private static class DefaultArtifactFactoryRequest extends BaseRequest implements ArtifactFactoryRequest
+ {
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String classifier;
+ private final String extension;
+ private final String type;
+
+ DefaultArtifactFactoryRequest( @Nonnull Session session,
+ String groupId,
+ String artifactId,
+ String version,
+ String classifier,
+ String extension,
+ String type )
+ {
+ super( session );
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ this.classifier = classifier;
+ this.extension = extension;
+ this.type = type;
+ }
+
+ @Override
+ public String getGroupId()
+ {
+ return groupId;
+ }
+
+ @Override
+ public String getArtifactId()
+ {
+ return artifactId;
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return version;
+ }
+
+ @Override
+ public String getClassifier()
+ {
+ return classifier;
+ }
+
+ @Override
+ public String getExtension()
+ {
+ return extension;
+ }
+
+ @Override
+ public String getType()
+ {
+ return type;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java
new file mode 100644
index 0000000000..5b07a88f84
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java
@@ -0,0 +1,74 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.Collections;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Installs {@link Artifact}s to the local repository.
+ *
+ * @since 4.0
+ * @see Session#withLocalRepository(org.apache.maven.api.LocalRepository)
+ */
+@Experimental
+public interface ArtifactInstaller extends Service
+{
+ /**
+ * @param request {@link ArtifactInstallerRequest}
+ * @throws ArtifactInstallerException in case of an error.
+ * @throws IllegalArgumentException in case {@code request} is {@code null}.
+ */
+ void install( ArtifactInstallerRequest request );
+
+ /**
+ * @param session the repository session
+ * @param artifact the {@link Artifact} to install
+ * @throws ArtifactInstallerException In case of an error which can be the a given artifact can not be found or the
+ * installation has failed.
+ * @throws IllegalArgumentException in case of parameter {@code session} is {@code null} or
+ * {@code artifact} is {@code null}.
+ */
+ default void install( Session session, Artifact artifact )
+ {
+ install( session, Collections.singletonList( artifact ) );
+ }
+
+ /**
+ * @param session the repository session
+ * @param artifacts Collection of {@link Artifact MavenArtifacts}
+ * @throws ArtifactInstallerException In case of an error which can be the a given artifact can not be found or the
+ * installation has failed.
+ * @throws IllegalArgumentException in case of parameter {@code request} is {@code null} or parameter
+ * {@code localRepository} is {@code null} or {@code localRepository} is not a directory
+ * or parameter {@code mavenArtifacts} is {@code null} or
+ * {@code mavenArtifacts.isEmpty()} is {@code true}.
+ */
+ default void install( Session session, Collection artifacts )
+ {
+ install( ArtifactInstallerRequest.build( session, artifacts ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java
new file mode 100644
index 0000000000..e6c6dc6abd
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java
@@ -0,0 +1,46 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * @since 4.0
+ */
+@Experimental
+public class ArtifactInstallerException
+ extends MavenException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3652561971360586373L;
+
+ /**
+ * @param message The message of the error.
+ * @param e {@link Exception}
+ */
+ public ArtifactInstallerException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
new file mode 100644
index 0000000000..772203a858
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
@@ -0,0 +1,113 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+
+/**
+ * A request for installing one or more artifacts in the local repository.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactInstallerRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ @Nonnull
+ Collection getArtifacts();
+
+ @Nonnull
+ static ArtifactInstallerRequestBuilder builder()
+ {
+ return new ArtifactInstallerRequestBuilder();
+ }
+
+ @Nonnull
+ static ArtifactInstallerRequest build( Session session, Collection artifacts )
+ {
+ return builder()
+ .session( session )
+ .artifacts( artifacts )
+ .build();
+ }
+
+ @NotThreadSafe
+ class ArtifactInstallerRequestBuilder
+ {
+ Session session;
+ Collection artifacts = Collections.emptyList();
+
+ @Nonnull
+ public ArtifactInstallerRequestBuilder session( @Nonnull Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactInstallerRequestBuilder artifacts( @Nullable Collection artifacts )
+ {
+ this.artifacts = artifacts != null ? artifacts : Collections.emptyList();
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactInstallerRequest build()
+ {
+ return new DefaultArtifactInstallerRequest( session, artifacts );
+ }
+
+ static class DefaultArtifactInstallerRequest extends BaseRequest
+ implements ArtifactInstallerRequest
+ {
+
+ private final Collection artifacts;
+
+ DefaultArtifactInstallerRequest( @Nonnull Session session,
+ @Nonnull Collection artifacts )
+ {
+ super( session );
+ this.artifacts = nonNull( artifacts, "artifacts can not be null" );
+ }
+
+ @Nonnull
+ @Override
+ public Collection getArtifacts()
+ {
+ return artifacts;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java
new file mode 100644
index 0000000000..4fa7713431
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java
@@ -0,0 +1,64 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Metadata;
+
+/**
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ArtifactManager extends Service
+{
+
+ /**
+ * Returns the path of the file previously associated to this artifact
+ * or {@code Optional.empty()} if no path has been associated.
+ */
+ @Nonnull
+ Optional getPath( @Nonnull Artifact artifact );
+
+ /**
+ * Associates the given file path to the artifact.
+ */
+ void setPath( @Nonnull Artifact artifact, Path path );
+
+ /**
+ * TODO: investigate removing the Metadata api completely
+ */
+ @Nonnull
+ Collection getAttachedMetadatas( @Nonnull Artifact artifact );
+
+ /**
+ * TODO: investigate removing the Metadata api completely
+ */
+ void attachMetadata( @Nonnull Artifact artifact, @Nonnull Metadata metadata );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java
new file mode 100644
index 0000000000..99f49d241d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java
@@ -0,0 +1,61 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Resolves the artifact, i.e download the file when required and attach it to the artifact
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ArtifactResolver extends Service
+{
+
+ /**
+ * @param request {@link ArtifactResolverRequest}
+ * @return {@link ArtifactResolverResult}
+ * @throws ArtifactResolverException in case of an error.
+ * @throws IllegalArgumentException in case of parameter {@code buildingRequest} is {@code null} or
+ * parameter {@code mavenArtifact} is {@code null} or invalid.
+ */
+ ArtifactResolverResult resolve( ArtifactResolverRequest request );
+
+ /**
+ * @param session {@link Session}
+ * @param coordinates array of {@link ArtifactCoordinate}
+ * @return {@link ArtifactResolverResult}
+ * @throws ArtifactResolverException in case of an error.
+ * @throws IllegalArgumentException in case of parameter {@code buildingRequest} is {@code null} or
+ * parameter {@code coordinate} is {@code null} or invalid.
+ */
+ default ArtifactResolverResult resolve( Session session,
+ Collection extends ArtifactCoordinate> coordinates )
+ {
+ return resolve( ArtifactResolverRequest.build( session, coordinates ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java
new file mode 100644
index 0000000000..ba6e5482cf
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java
@@ -0,0 +1,45 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ *
+ *
+ * @since 4.0
+ */
+@Experimental
+public class ArtifactResolverException
+ extends MavenException
+{
+
+ private static final long serialVersionUID = 7252294837746943917L;
+
+ /**
+ * @param message The message for the exception.
+ * @param e The exception itself.
+ */
+ public ArtifactResolverException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
new file mode 100644
index 0000000000..f35f326f14
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
@@ -0,0 +1,108 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+/**
+ * A request for resolving an artifact.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactResolverRequest
+{
+ @Nonnull
+ Session getSession();
+
+ @Nonnull
+ Collection extends ArtifactCoordinate> getCoordinates();
+
+ @Nonnull
+ static ArtifactResolverRequestBuilder builder()
+ {
+ return new ArtifactResolverRequestBuilder();
+ }
+
+ @Nonnull
+ static ArtifactResolverRequest build( Session session, Collection extends ArtifactCoordinate> coordinates )
+ {
+ return builder()
+ .session( session )
+ .coordinates( coordinates )
+ .build();
+ }
+
+ @NotThreadSafe
+ class ArtifactResolverRequestBuilder
+ {
+ Session session;
+ Collection extends ArtifactCoordinate> coordinates;
+
+ @Nonnull
+ public ArtifactResolverRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactResolverRequestBuilder coordinates( Collection extends ArtifactCoordinate> coordinates )
+ {
+ this.coordinates = coordinates;
+ return this;
+ }
+
+ @Nonnull
+ public ArtifactResolverRequest build()
+ {
+ return new DefaultArtifactResolverRequest( session, coordinates );
+ }
+
+ private static class DefaultArtifactResolverRequest extends BaseRequest implements ArtifactResolverRequest
+ {
+ @Nonnull
+ private final Collection extends ArtifactCoordinate> coordinates;
+
+ DefaultArtifactResolverRequest( @Nonnull Session session,
+ @Nonnull Collection extends ArtifactCoordinate> coordinates )
+ {
+ super( session );
+ this.coordinates = nonNull( coordinates, "coordinates can not be null" );
+ }
+
+ @Nonnull
+ @Override
+ public Collection extends ArtifactCoordinate> getCoordinates()
+ {
+ return coordinates;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
new file mode 100644
index 0000000000..74bd5a7411
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
@@ -0,0 +1,43 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.nio.file.Path;
+import java.util.Map;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The Artifact Result
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ArtifactResolverResult
+{
+ /**
+ * @return {@link Artifact}
+ */
+ @Nonnull
+ Map getArtifacts();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
new file mode 100644
index 0000000000..86afa5a20d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
@@ -0,0 +1,67 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.Session;
+
+/**
+ * Base class for requests.
+ *
+ * @since 4.0
+ */
+@Experimental
+abstract class BaseRequest
+{
+
+ private final Session session;
+
+ protected BaseRequest( @Nonnull Session session )
+ {
+ this.session = nonNull( session, "session can not be null" );
+ }
+
+ @Nonnull
+ public Session getSession()
+ {
+ return session;
+ }
+
+ public static T nonNull( T obj, String message )
+ {
+ if ( obj == null )
+ {
+ throw new IllegalArgumentException( message );
+ }
+ return obj;
+ }
+
+ protected static Collection unmodifiable( Collection obj )
+ {
+ return obj != null && !obj.isEmpty()
+ ? Collections.unmodifiableCollection( new ArrayList<>( obj ) ) : Collections.emptyList();
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java
new file mode 100644
index 0000000000..e21b2c4692
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java
@@ -0,0 +1,117 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Project;
+
+/**
+ * The DependencyCollector service can be used to collect dependencies
+ * for a given artifact and builds a graph of them.
+ * The dependencies collection mechanism will not download any artifacts,
+ * and only the pom files will be downloaded.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface DependencyCollector extends Service
+{
+
+ /**
+ * Collects the transitive dependencies and builds a dependency graph.
+ * Note that this operation is only concerned about determining the coordinates of the
+ * transitive dependencies and does not actually resolve the artifact files.
+ *
+ * @param request The dependency collection request, must not be {@code null}.
+ * @return The collection result, never {@code null}.
+ * @throws DependencyCollectorException If the dependency tree could not be built.
+ * @throws IllegalArgumentException if an argument is null or invalid
+ *
+ * @see DependencyCollector#collect(Session, Project)
+ * @see DependencyCollector#collect(Session, DependencyCoordinate)
+ * @see DependencyCollector#collect(Session, Artifact)
+ */
+ @Nonnull
+ DependencyCollectorResult collect( @Nonnull DependencyCollectorRequest request );
+
+ /**
+ * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+ * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+ * artifact files.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param root The Maven Dependency, must not be {@code null}.
+ * @return The collection result, never {@code null}.
+ * @throws DependencyCollectorException If the dependency tree could not be built.
+ * @throws IllegalArgumentException if an argument is null or invalid
+ * @see #collect(DependencyCollectorRequest)
+ */
+ @Nonnull
+ default DependencyCollectorResult collect( @Nonnull Session session,
+ @Nonnull DependencyCoordinate root )
+ {
+ return collect( DependencyCollectorRequest.build( session, root ) );
+ }
+
+ /**
+ * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+ * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+ * artifact files.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param project The {@link Project}, must not be {@code null}.
+ * @return The collection result, never {@code null}.
+ * @throws DependencyCollectorException If the dependency tree could not be built.
+ * @throws IllegalArgumentException if an argument is null or invalid
+ * @see #collect(DependencyCollectorRequest)
+ */
+ @Nonnull
+ default DependencyCollectorResult collect( @Nonnull Session session,
+ @Nonnull Project project )
+ {
+ return collect( DependencyCollectorRequest.build( session, project ) );
+ }
+
+ /**
+ * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+ * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+ * artifact files.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param artifact The {@link Artifact}, must not be {@code null}.
+ * @return The collection result, never {@code null}.
+ * @throws DependencyCollectorException If the dependency tree could not be built.
+ * @throws IllegalArgumentException if an argument is null or invalid
+ * @see #collect(DependencyCollectorRequest)
+ */
+ @Nonnull
+ default DependencyCollectorResult collect( @Nonnull Session session,
+ @Nonnull Artifact artifact )
+ {
+ return collect( DependencyCollectorRequest.build( session, artifact ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java
new file mode 100644
index 0000000000..019fedb6b3
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java
@@ -0,0 +1,47 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Thrown in case of bad artifact descriptors, version ranges or other
+ * issues encountered during calculation of the dependency graph.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class DependencyCollectorException
+ extends MavenException
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3134726259840210686L;
+
+ /**
+ * @param message The message you would give for the exception.
+ * @param cause The cause which is related to the message.
+ */
+ public DependencyCollectorException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java
new file mode 100644
index 0000000000..b0963205d6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java
@@ -0,0 +1,331 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to
+ * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct
+ * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies
+ * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in
+ * which case the root node of the resulting graph has no associated dependency.
+ *
+ * @since 4.0
+ * @see DependencyCollector#collect(DependencyCollectorRequest)
+ */
+@Experimental
+@Immutable
+public interface DependencyCollectorRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ @Nonnull
+ Optional getRootArtifact();
+
+ @Nonnull
+ Optional getRoot();
+
+ @Nonnull
+ Collection getDependencies();
+
+ @Nonnull
+ Collection getManagedDependencies();
+
+ boolean getVerbose();
+
+ @Nonnull
+ static DependencyCollectorRequest build( @Nonnull Session session, Artifact root )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .rootArtifact( nonNull( root, "root can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static DependencyCollectorRequest build( @Nonnull Session session, @Nonnull DependencyCoordinate root )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .root( nonNull( root, "root can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static DependencyCollectorRequest build( @Nonnull Session session, @Nonnull Project project )
+ {
+ nonNull( session, "session can not be null" );
+ nonNull( project, "project can not be null" );
+ return builder()
+ .session( session )
+ .rootArtifact( project.getArtifact() )
+ .dependencies( project.getDependencies() )
+ .managedDependencies( project.getManagedDependencies() )
+ .build();
+ }
+
+ @Nonnull
+ static DependencyCollectorRequestBuilder builder()
+ {
+ return new DependencyCollectorRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class DependencyCollectorRequestBuilder
+ {
+
+ Session session;
+ Artifact rootArtifact;
+ DependencyCoordinate root;
+ List dependencies = Collections.emptyList();
+ List managedDependencies = Collections.emptyList();
+ boolean verbose;
+
+ @Nonnull
+ public DependencyCollectorRequestBuilder session( @Nonnull Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ /**
+ * Sets the root artifact for the dependency graph.
+ * This must not be confused with {@link #root(DependencyCoordinate)}: The root dependency , like any
+ * other specified dependency, will be subject to dependency collection/resolution, i.e. should have an artifact
+ * descriptor and a corresponding artifact file. The root artifact on the other hand is only used
+ * as a label for the root node of the graph in case no root dependency was specified. As such, the configured
+ * root artifact is ignored if {@link #root(DependencyCoordinate)} has been set.
+ *
+ * @param rootArtifact The root artifact for the dependency graph, may be {@code null}.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder rootArtifact( @Nullable Artifact rootArtifact )
+ {
+ this.rootArtifact = rootArtifact;
+ return this;
+ }
+
+ /**
+ * @param root The root dependency
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder root( @Nonnull DependencyCoordinate root )
+ {
+ this.root = root;
+ return this;
+ }
+
+ /**
+ * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the
+ * direct dependencies from the request will be merged with the direct dependencies from the root dependency's
+ * artifact descriptor, giving higher priority to the dependencies from the request.
+ *
+ * @param dependencies The direct dependencies, may be {@code null}.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder dependencies( @Nullable List dependencies )
+ {
+ this.dependencies = ( dependencies != null ) ? dependencies : Collections.emptyList();
+ return this;
+ }
+
+ /**
+ * Adds the specified direct dependency.
+ *
+ * @param dependency The dependency to add, may be {@code null}.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder dependency( @Nullable DependencyCoordinate dependency )
+ {
+ if ( dependency != null )
+ {
+ if ( this.dependencies.isEmpty() )
+ {
+ this.dependencies = new ArrayList<>();
+ }
+ this.dependencies.add( dependency );
+ }
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not
+ * apply to
+ * the direct dependencies of the root node.
+ *
+ * @param managedDependencies The dependency management, may be {@code null}.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder managedDependencies(
+ @Nullable List managedDependencies )
+ {
+ this.managedDependencies = ( managedDependencies != null ) ? managedDependencies : Collections.emptyList();
+ return this;
+ }
+
+ /**
+ * Adds the specified managed dependency.
+ *
+ * @param managedDependency The managed dependency to add, may be {@code null} in which case the call
+ * will have no effect.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder managedDependency( @Nullable DependencyCoordinate managedDependency )
+ {
+ if ( managedDependency != null )
+ {
+ if ( this.managedDependencies.isEmpty() )
+ {
+ this.managedDependencies = new ArrayList<>();
+ }
+ this.managedDependencies.add( managedDependency );
+ }
+ return this;
+ }
+
+ /**
+ * Specifies that the collection should be verbose.
+ *
+ * @param verbose whether the collection should be verbose or not.
+ * @return This request for chaining, never {@code null}.
+ */
+ @Nonnull
+ public DependencyCollectorRequestBuilder verbose( boolean verbose )
+ {
+ this.verbose = verbose;
+ return this;
+ }
+
+ @Nonnull
+ public DependencyCollectorRequest build()
+ {
+ return new DefaultDependencyCollectorRequest(
+ session,
+ rootArtifact,
+ root,
+ dependencies,
+ managedDependencies,
+ verbose );
+ }
+
+ static class DefaultDependencyCollectorRequest extends BaseRequest
+ implements DependencyCollectorRequest
+ {
+ private final Artifact rootArtifact;
+ private final DependencyCoordinate root;
+ private final Collection dependencies;
+ private final Collection managedDependencies;
+ private final boolean verbose;
+
+
+ /**
+ * Creates a request with the specified properties.
+ *
+ * @param session {@link Session}
+ * @param rootArtifact The root dependency whose transitive dependencies should be collected, may be {@code
+ * null}.
+ */
+ DefaultDependencyCollectorRequest(
+ @Nonnull Session session,
+ @Nullable Artifact rootArtifact,
+ @Nullable DependencyCoordinate root,
+ @Nonnull Collection dependencies,
+ @Nonnull Collection managedDependencies,
+ boolean verbose )
+ {
+ super( session );
+ this.rootArtifact = rootArtifact;
+ this.root = root;
+ this.dependencies = unmodifiable( dependencies );
+ this.managedDependencies = unmodifiable( managedDependencies );
+ this.verbose = verbose;
+ }
+
+ @Nonnull
+ @Override
+ public Optional getRootArtifact()
+ {
+ return Optional.ofNullable( rootArtifact );
+ }
+
+ @Nonnull
+ @Override
+ public Optional getRoot()
+ {
+ return Optional.ofNullable( root );
+ }
+
+ @Nonnull
+ @Override
+ public Collection getDependencies()
+ {
+ return dependencies;
+ }
+
+ @Nonnull
+ @Override
+ public Collection getManagedDependencies()
+ {
+ return managedDependencies;
+ }
+
+ @Override
+ public boolean getVerbose()
+ {
+ return verbose;
+ }
+
+ @Nonnull
+ @Override
+ public String toString()
+ {
+ return getRoot() + " -> " + getDependencies();
+ }
+
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java
new file mode 100644
index 0000000000..09388cca75
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java
@@ -0,0 +1,50 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.List;
+
+import org.apache.maven.api.Node;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The result of a dependency collection request.
+ *
+ * @since 4.0
+ * @see DependencyCollector#collect(DependencyCollectorRequest)
+ */
+@Experimental
+public interface DependencyCollectorResult
+{
+ /**
+ * Gets the exceptions that occurred while building the dependency graph.
+ *
+ * @return The exceptions that occurred, never {@code null}.
+ */
+ List getExceptions();
+
+ /**
+ * Gets the root node of the dependency graph.
+ *
+ * @return The root node of the dependency graph or {@code null} if none.
+ */
+ Node getRoot();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java
new file mode 100644
index 0000000000..d3c7a6ffd7
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java
@@ -0,0 +1,89 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.ReportPlugin;
+
+/**
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface DependencyCoordinateFactory extends Service
+{
+
+ /**
+ * Creates a new {@link DependencyCoordinate} object from the request.
+ *
+ * @param request the request containing the various data
+ * @return a new {@link DependencyCoordinate} object.
+ *
+ * @throws IllegalArgumentException if {@code request} is null or
+ * if {@code request.getSession()} is null or invalid
+ */
+ @Nonnull
+ DependencyCoordinate create( @Nonnull DependencyCoordinateFactoryRequest request );
+
+ @Nonnull
+ default DependencyCoordinate create( @Nonnull Session session, @Nonnull ArtifactCoordinate coordinate )
+ {
+ return create( DependencyCoordinateFactoryRequest.build( session, coordinate ) );
+ }
+
+ @Nonnull
+ default DependencyCoordinate create( @Nonnull Session session, @Nonnull org.apache.maven.api.Dependency dependency )
+ {
+ return create( DependencyCoordinateFactoryRequest.build( session, dependency ) );
+ }
+
+ @Nonnull
+ default DependencyCoordinate create( @Nonnull Session session, Dependency dependency )
+ {
+ return create( DependencyCoordinateFactoryRequest.build( session,
+ dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(),
+ dependency.getClassifier(), null, dependency.getType() ) );
+ }
+
+ @Nonnull
+ default DependencyCoordinate create( @Nonnull Session session, Plugin plugin )
+ {
+ // TODO: hard coded string
+ return create( DependencyCoordinateFactoryRequest.build( session,
+ plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(),
+ null, null, "maven-plugin" ) );
+ }
+
+ @Nonnull
+ default DependencyCoordinate create( @Nonnull Session session, ReportPlugin reportPlugin )
+ {
+ // TODO: hard coded string
+ return create( DependencyCoordinateFactoryRequest.build( session,
+ reportPlugin.getGroupId(), reportPlugin.getArtifactId(), reportPlugin.getVersion(),
+ null, null, "maven-plugin" ) );
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java
new file mode 100644
index 0000000000..b42853cd5c
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java
@@ -0,0 +1,292 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.Exclusion;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+/**
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface DependencyCoordinateFactoryRequest extends ArtifactCoordinateFactoryRequest
+{
+
+ String getScope();
+
+ boolean isOptional();
+
+ @Nonnull
+ Collection getExclusions();
+
+ static DependencyCoordinateFactoryRequest build( Session session, String groupId, String artifactId,
+ String version, String classifier, String extension, String type )
+ {
+ return DependencyCoordinateFactoryRequest.builder()
+ .session( session )
+ .groupId( groupId )
+ .artifactId( artifactId )
+ .version( version )
+ .classifier( classifier )
+ .extension( extension )
+ .type( type )
+ .build();
+ }
+
+ static DependencyCoordinateFactoryRequest build( Session session, ArtifactCoordinate coordinate )
+ {
+ return builder()
+ .session( session )
+ .groupId( coordinate.getGroupId() )
+ .artifactId( coordinate.getArtifactId() )
+ .version( coordinate.getVersion().asString() )
+ .classifier( coordinate.getClassifier() )
+ .extension( coordinate.getExtension() )
+ .build();
+ }
+
+ static DependencyCoordinateFactoryRequest build( Session session, Dependency dependency )
+ {
+ return builder()
+ .session( session )
+ .groupId( dependency.getGroupId() )
+ .artifactId( dependency.getArtifactId() )
+ .version( dependency.getVersion().asString() )
+ .classifier( dependency.getClassifier() )
+ .extension( dependency.getExtension() )
+ .type( dependency.getType().getName() )
+ .scope( dependency.getScope().id() )
+ .optional( dependency.isOptional() )
+ .build();
+ }
+
+ static DependencyCoordinateFactoryRequestBuilder builder()
+ {
+ return new DependencyCoordinateFactoryRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class DependencyCoordinateFactoryRequestBuilder
+ {
+ private Session session;
+ private String groupId;
+ private String artifactId;
+ private String version;
+ private String classifier;
+ private String extension;
+ private String type;
+ private String scope;
+ private boolean optional;
+ private Collection exclusions = Collections.emptyList();
+
+ public DependencyCoordinateFactoryRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder groupId( String groupId )
+ {
+ this.groupId = groupId;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder artifactId( String artifactId )
+ {
+ this.artifactId = artifactId;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder version( String version )
+ {
+ this.version = version;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder classifier( String classifier )
+ {
+ this.classifier = classifier;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder extension( String extension )
+ {
+ this.extension = extension;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder type( String type )
+ {
+ this.type = type;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder scope( String scope )
+ {
+ this.scope = scope;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder optional( boolean optional )
+ {
+ this.optional = optional;
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder exclusions( Collection exclusions )
+ {
+ if ( exclusions != null )
+ {
+ if ( this.exclusions.isEmpty() )
+ {
+ this.exclusions = new ArrayList<>();
+ }
+ this.exclusions.addAll( exclusions );
+ }
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequestBuilder exclusion( Exclusion exclusion )
+ {
+ if ( exclusion != null )
+ {
+ if ( this.exclusions.isEmpty() )
+ {
+ this.exclusions = new ArrayList<>();
+ }
+ this.exclusions.add( exclusion );
+ }
+ return this;
+ }
+
+ public DependencyCoordinateFactoryRequest build()
+ {
+ return new DefaultDependencyCoordinateFactoryRequest( session, groupId, artifactId, version,
+ classifier, extension, type, scope, optional, exclusions );
+ }
+
+ private static class DefaultDependencyCoordinateFactoryRequest
+ extends BaseRequest
+ implements DependencyCoordinateFactoryRequest
+ {
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String classifier;
+ private final String extension;
+ private final String type;
+ private final String scope;
+ private final boolean optional;
+ private final Collection exclusions;
+
+ @SuppressWarnings( "checkstyle:ParameterNumber" )
+ private DefaultDependencyCoordinateFactoryRequest(
+ @Nonnull Session session, String groupId,
+ String artifactId,
+ String version,
+ String classifier,
+ String extension,
+ String type,
+ String scope,
+ boolean optional,
+ Collection exclusions )
+ {
+ super( session );
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ this.classifier = classifier;
+ this.extension = extension;
+ this.type = type;
+ this.scope = scope;
+ this.optional = optional;
+ this.exclusions = exclusions;
+ }
+
+ @Override
+ public String getGroupId()
+ {
+ return groupId;
+ }
+
+ @Override
+ public String getArtifactId()
+ {
+ return artifactId;
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return version;
+ }
+
+ @Override
+ public String getClassifier()
+ {
+ return classifier;
+ }
+
+ @Override
+ public String getExtension()
+ {
+ return extension;
+ }
+
+ @Override
+ public String getType()
+ {
+ return type;
+ }
+
+ @Override
+ public String getScope()
+ {
+ return scope;
+ }
+
+ @Override
+ public boolean isOptional()
+ {
+ return optional;
+ }
+
+ @Nonnull
+ @Override
+ public Collection getExclusions()
+ {
+ return exclusions;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java
new file mode 100644
index 0000000000..5e40ac83fb
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java
@@ -0,0 +1,48 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.nio.file.Path;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.Metadata;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface LocalRepositoryManager extends Service
+{
+
+ Path getPathForLocalArtifact( Session session, LocalRepository local, Artifact artifact );
+
+ Path getPathForLocalMetadata( Session session, LocalRepository local, Metadata metadata );
+
+ Path getPathForRemoteArtifact( Session session, LocalRepository local, RemoteRepository remote, Artifact artifact );
+
+ Path getPathForRemoteMetadata( Session session, LocalRepository local, RemoteRepository remote, Metadata metadata );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java
new file mode 100644
index 0000000000..93e24994ed
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java
@@ -0,0 +1,38 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.apache.maven.api.Service;
+
+public interface Lookup extends Service
+{
+
+ T lookup( Class type );
+
+ T lookup( Class type, String name );
+
+ List lookupList( Class type );
+
+ Map lookupMap( Class type );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java
new file mode 100644
index 0000000000..d88549112e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java
@@ -0,0 +1,50 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link Lookup} service.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class LookupException
+ extends MavenException
+{
+ /**
+ * @param message The message to give.
+ * @param e The {@link Exception}.
+ */
+ public LookupException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+ /**
+ * @param e The {@link Exception}.
+ */
+ public LookupException( Exception e )
+ {
+ super( e );
+ }
+
+}
diff --git a/maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
similarity index 52%
rename from maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java
rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
index 39ffb7ef92..aba7dd7219 100644
--- a/maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
@@ -1,4 +1,4 @@
-package org.apache.maven.settings;
+package org.apache.maven.api.services;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,37 +19,33 @@ package org.apache.maven.settings;
* under the License.
*/
-import java.io.File;
+import org.apache.maven.api.annotations.Experimental;
/**
- * To handle runtime information like local repository or profiles.
+ * Base class for all maven exceptions.
*
+ * @since 4.0
*/
-@Deprecated
-public class RuntimeInfo
+@Experimental
+public class MavenException extends RuntimeException
{
- @SuppressWarnings( "checkstyle:constantname" )
- public static final String userHome = System.getProperty( "user.home" );
-
- @SuppressWarnings( "checkstyle:constantname" )
- public static final File userMavenConfigurationHome = new File( userHome, ".m2" );
-
- public static final File DEFAULT_USER_SETTINGS_FILE = new File( userMavenConfigurationHome, "settings.xml" );
-
- private File settings;
-
- public RuntimeInfo()
+ public MavenException()
{
- this.settings = DEFAULT_USER_SETTINGS_FILE;
}
- public RuntimeInfo( File settings )
+ public MavenException( String message )
{
- this.settings = settings;
+ super( message );
}
- public File getFile()
+ public MavenException( String message, Throwable cause )
{
- return settings;
+ super( message, cause );
}
+
+ public MavenException( Throwable cause )
+ {
+ super( cause );
+ }
+
}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java
new file mode 100644
index 0000000000..1d86911995
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java
@@ -0,0 +1,157 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Message builder that supports configurable styling.
+ *
+ * @since 4.0
+ * @see MessageBuilderFactory
+ */
+public interface MessageBuilder
+{
+ /**
+ * Append message content in success style.
+ * By default, bold green
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder success( Object message );
+
+ /**
+ * Append message content in warning style.
+ * By default, bold yellow
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder warning( Object message );
+
+ /**
+ * Append message content in failure style.
+ * By default, bold red
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder failure( Object message );
+
+ /**
+ * Append message content in strong style.
+ * By default, bold
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder strong( Object message );
+
+ /**
+ * Append message content in mojo style.
+ * By default, green
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder mojo( Object message );
+
+ /**
+ * Append message content in project style.
+ * By default, cyan
+ * @param message the message to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder project( Object message );
+
+ //
+ // message building methods modelled after Ansi methods
+ //
+ /**
+ * Append content to the message buffer.
+ * @param value the content to append
+ * @param offset the index of the first {@code char} to append
+ * @param len the number of {@code char}s to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder a( char[] value, int offset, int len );
+
+ /**
+ * Append content to the message buffer.
+ * @param value the content to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder a( char[] value );
+
+ /**
+ * Append content to the message buffer.
+ * @param value the content to append
+ * @param start the starting index of the subsequence to be appended
+ * @param end the end index of the subsequence to be appended
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder a( CharSequence value, int start, int end );
+
+ /**
+ * Append content to the message buffer.
+ * @param value the content to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder a( CharSequence value );
+
+ /**
+ * Append content to the message buffer.
+ * @param value the content to append
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder a( Object value );
+
+ /**
+ * Append newline to the message buffer.
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder newline();
+
+ /**
+ * Append formatted content to the buffer.
+ * @see String#format(String, Object...)
+ * @param pattern a format string
+ * @param args arguments referenced by the format specifiers in the format string.
+ * @return the current builder
+ */
+ @Nonnull
+ MessageBuilder format( String pattern, Object... args );
+
+ /**
+ * Return the built message.
+ * @return the message
+ */
+ @Nonnull
+ String build();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java
new file mode 100644
index 0000000000..5290dab148
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java
@@ -0,0 +1,71 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A factory for {@link MessageBuilder}.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface MessageBuilderFactory extends Service
+{
+ /**
+ * Checks if the underlying output does support styling or not.
+ * @return whether color styling is supported or not
+ */
+ boolean isColorEnabled();
+
+ /**
+ * Returns the terminal width or -1
if not supported.
+ * @return the terminal width
+ */
+ int getTerminalWidth();
+
+ /**
+ * Creates a new message builder.
+ * @return a new message builder
+ */
+ @Nonnull
+ MessageBuilder builder();
+
+ /**
+ * Creates a new message builder backed by the given string builder.
+ * @param stringBuilder a string builder
+ * @return a new message builder
+ */
+ @Nonnull
+ MessageBuilder builder( @Nonnull StringBuilder stringBuilder );
+
+ /**
+ * Creates a new message builder of the specified size.
+ * @param size the initial size of the message builder buffer
+ * @return a new message builder
+ */
+ @Nonnull
+ default MessageBuilder builder( int size )
+ {
+ return builder( new StringBuilder( size ) );
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
new file mode 100644
index 0000000000..d7829752f9
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
@@ -0,0 +1,110 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+
+/**
+ * @since 4.0
+ */
+@Experimental
+public interface ProjectBuilder extends Service
+{
+
+ /**
+ * Creates a {@link org.apache.maven.api.Project} from a POM file.
+ *
+ * @param request {@link ProjectBuilderRequest}
+ * @return the {@link ProjectBuilderResult} containing the built project and possible errors
+ * @throws ProjectBuilderException if the project can not be created
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ */
+ @Nonnull
+ ProjectBuilderResult build( ProjectBuilderRequest request );
+
+ /**
+ * Creates a {@link org.apache.maven.api.Project} from a POM file.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param source The {@link ProjectBuilderSource}, must not be {@code null}.
+ * @throws ProjectBuilderException if the project can not be created
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ * @see #build(ProjectBuilderRequest)
+ */
+ @Nonnull
+ default ProjectBuilderResult build( @Nonnull Session session, @Nonnull ProjectBuilderSource source )
+ {
+ return build( ProjectBuilderRequest.build( session, source ) );
+ }
+
+ /**
+ * Creates a {@link org.apache.maven.api.Project} from a POM file.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param path The {@link Path}, must not be {@code null}.
+ * @throws ProjectBuilderException if the project can not be created
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ * @see #build(ProjectBuilderRequest)
+ */
+ @Nonnull
+ default ProjectBuilderResult build( @Nonnull Session session, @Nonnull Path path )
+ {
+ return build( ProjectBuilderRequest.build( session, path ) );
+ }
+
+ /**
+ * Creates a {@link org.apache.maven.api.Project} from an artifact.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param artifact The {@link Artifact}, must not be {@code null}.
+ * @throws ProjectBuilderException if the project can not be created
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ * @see #build(ProjectBuilderRequest)
+ */
+ @Nonnull
+ default ProjectBuilderResult build( @Nonnull Session session, @Nonnull Artifact artifact )
+ {
+ return build( ProjectBuilderRequest.build( session, artifact ) );
+ }
+
+ /**
+ * Creates a {@link org.apache.maven.api.Project} from a coordinate.
+ *
+ * @param session The {@link Session}, must not be {@code null}.
+ * @param coordinate The {@link ArtifactCoordinate}, must not be {@code null}.
+ * @throws ProjectBuilderException if the project can not be created
+ * @throws IllegalArgumentException if an argument is {@code null} or invalid
+ * @see #build(ProjectBuilderRequest)
+ */
+ @Nonnull
+ default ProjectBuilderResult build( @Nonnull Session session, @Nonnull ArtifactCoordinate coordinate )
+ {
+ return build( ProjectBuilderRequest.build( session, coordinate ) );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java
new file mode 100644
index 0000000000..2256bd1446
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java
@@ -0,0 +1,42 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link ProjectBuilder} service.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class ProjectBuilderException
+ extends MavenException
+{
+ /**
+ * @param message The message to give.
+ * @param e The {@link Exception}.
+ */
+ public ProjectBuilderException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java
new file mode 100644
index 0000000000..fef6ceae0d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java
@@ -0,0 +1,90 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Describes a problem that was encountered during project building. A problem can either be an exception that was
+ * thrown or a simple string message. In addition, a problem carries a hint about its source.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ProjectBuilderProblem
+{
+
+ /**
+ * Gets the hint about the source of the problem. While the syntax of this hint is unspecified and depends on the
+ * creator of the problem, the general expectation is that the hint provides sufficient information to the user to
+ * track the problem back to its origin. A concrete example for such a source hint can be the file path or URL from
+ * which the settings were read.
+ *
+ * @return The hint about the source of the problem or an empty string if unknown, never {@code null}.
+ */
+ String getSource();
+
+ /**
+ * Gets the one-based index of the line containing the problem. The line number should refer to some text file that
+ * is given by {@link #getSource()}.
+ *
+ * @return The one-based index of the line containing the problem or a non-positive value if unknown.
+ */
+ int getLineNumber();
+
+ /**
+ * Gets the one-based index of the column containing the problem. The column number should refer to some text file
+ * that is given by {@link #getSource()}.
+ *
+ * @return The one-based index of the column containing the problem or non-positive value if unknown.
+ */
+ int getColumnNumber();
+
+ /**
+ * Gets the location of the problem. The location is a user-friendly combination of the values from
+ * {@link #getSource()}, {@link #getLineNumber()} and {@link #getColumnNumber()}. The exact syntax of the returned
+ * value is undefined.
+ *
+ * @return The location of the problem, never {@code null}.
+ */
+ String getLocation();
+
+ /**
+ * Gets the exception that caused this problem (if any).
+ *
+ * @return The exception that caused this problem or {@code null} if not applicable.
+ */
+ Exception getException();
+
+ /**
+ * Gets the message that describes this problem.
+ *
+ * @return The message describing this problem, never {@code null}.
+ */
+ String getMessage();
+
+ /**
+ * Gets the severity level of this problem.
+ *
+ * @return The severity level of this problem, never {@code null}.
+ */
+ ProjectBuilderProblemSeverity getSeverity();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java
new file mode 100644
index 0000000000..6af0257098
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java
@@ -0,0 +1,37 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The different severity levels for a problem, in decreasing order.
+ *
+ * @since 4.0
+ */
+@Experimental
+public enum ProjectBuilderProblemSeverity
+{
+
+ FATAL, //
+ ERROR, //
+ WARNING //
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
new file mode 100644
index 0000000000..4b90e8bfd5
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -0,0 +1,262 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Artifact;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * Request used to build a {@link org.apache.maven.api.Project} using
+ * the {@link ProjectBuilder} service.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface ProjectBuilderRequest
+{
+
+ @Nonnull
+ Session getSession();
+
+ @Nonnull
+ Optional getPath();
+
+ @Nonnull
+ Optional getSource();
+
+ @Nonnull
+ Optional getArtifact();
+
+ @Nonnull
+ Optional getCoordinate();
+
+ boolean isAllowStubModel();
+
+ boolean isRecursive();
+
+ boolean isProcessPlugins();
+
+ boolean isResolveDependencies();
+
+ @Nonnull
+ static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull ProjectBuilderSource source )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .source( nonNull( source, "source can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull Path path )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .path( nonNull( path, "path can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull Artifact artifact )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .artifact( nonNull( artifact, "artifact can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull ArtifactCoordinate coordinate )
+ {
+ return builder()
+ .session( nonNull( session, "session can not be null" ) )
+ .coordinate( nonNull( coordinate, "coordinate can not be null" ) )
+ .build();
+ }
+
+ @Nonnull
+ static ProjectBuilderRequestBuilder builder()
+ {
+ return new ProjectBuilderRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class ProjectBuilderRequestBuilder
+ {
+ Session session;
+ Path path;
+ ProjectBuilderSource source;
+ Artifact artifact;
+ ArtifactCoordinate coordinate;
+ boolean allowStubModel;
+ boolean recursive;
+ boolean processPlugins = true;
+ boolean resolveDependencies = true;
+
+ public ProjectBuilderRequestBuilder session( Session session )
+ {
+ this.session = session;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder path( Path path )
+ {
+ this.path = path;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder source( ProjectBuilderSource source )
+ {
+ this.source = source;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder artifact( Artifact artifact )
+ {
+ this.artifact = artifact;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder coordinate( ArtifactCoordinate coordinate )
+ {
+ this.coordinate = coordinate;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder processPlugins( boolean processPlugins )
+ {
+ this.processPlugins = processPlugins;
+ return this;
+ }
+
+ public ProjectBuilderRequestBuilder resolveDependencies( boolean resolveDependencies )
+ {
+ this.resolveDependencies = resolveDependencies;
+ return this;
+ }
+
+ public ProjectBuilderRequest build()
+ {
+ return new DefaultProjectBuilderRequest( session, path, source, artifact, coordinate,
+ allowStubModel, recursive, processPlugins, resolveDependencies );
+ }
+
+ private static class DefaultProjectBuilderRequest extends BaseRequest
+ implements ProjectBuilderRequest
+ {
+ private final Path path;
+ private final ProjectBuilderSource source;
+ private final Artifact artifact;
+ private final ArtifactCoordinate coordinate;
+ private final boolean allowStubModel;
+ private final boolean recursive;
+ private final boolean processPlugins;
+ private final boolean resolveDependencies;
+
+ @SuppressWarnings( "checkstyle:ParameterNumber" )
+ DefaultProjectBuilderRequest( @Nonnull Session session,
+ @Nullable Path path,
+ @Nullable ProjectBuilderSource source,
+ @Nullable Artifact artifact,
+ @Nullable ArtifactCoordinate coordinate,
+ boolean allowStubModel,
+ boolean recursive,
+ boolean processPlugins,
+ boolean resolveDependencies )
+ {
+ super( session );
+ this.path = path;
+ this.source = source;
+ this.artifact = artifact;
+ this.coordinate = coordinate;
+ this.allowStubModel = allowStubModel;
+ this.recursive = recursive;
+ this.processPlugins = processPlugins;
+ this.resolveDependencies = resolveDependencies;
+ }
+
+ @Nonnull
+ @Override
+ public Optional getPath()
+ {
+ return Optional.ofNullable( path );
+ }
+
+ @Nonnull
+ @Override
+ public Optional getSource()
+ {
+ return Optional.ofNullable( source );
+ }
+
+ @Nonnull
+ @Override
+ public Optional getArtifact()
+ {
+ return Optional.ofNullable( artifact );
+ }
+
+ @Nonnull
+ @Override
+ public Optional getCoordinate()
+ {
+ return Optional.ofNullable( coordinate );
+ }
+
+ @Override
+ public boolean isAllowStubModel()
+ {
+ return allowStubModel;
+ }
+
+ @Override
+ public boolean isRecursive()
+ {
+ return recursive;
+ }
+
+ @Override
+ public boolean isProcessPlugins()
+ {
+ return processPlugins;
+ }
+
+ @Override
+ public boolean isResolveDependencies()
+ {
+ return resolveDependencies;
+ }
+ }
+
+ }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
new file mode 100644
index 0000000000..a76b6cab2f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
@@ -0,0 +1,83 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Optional;
+
+import org.apache.maven.api.Project;
+
+/**
+ * Result of a project build call.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ProjectBuilderResult
+{
+
+ /**
+ * Gets the identifier of the project that could not be built. The general format of the identifier is {@code
+ * ::} but some of these coordinates may still be unknown at the point the exception
+ * is thrown so this information is merely meant to assist the user.
+ *
+ * @return The identifier of the project or an empty string if not known, never {@code null}.
+ */
+ @Nonnull
+ String getProjectId();
+
+ /**
+ * Gets the POM file from which the project was built.
+ *
+ * @return The optional POM file.
+ */
+ @Nonnull
+ Optional getPomFile();
+
+ /**
+ * Gets the project that was built.
+ *
+ * @return The project that was built or {@code null} if an error occurred and this result accompanies a
+ * {@link ProjectBuilderException}.
+ */
+ @Nonnull
+ Optional getProject();
+
+ /**
+ * Gets the problems that were encountered during the project building.
+ *
+ * @return The problems that were encountered during the project building, can be empty but never {@code null}.
+ */
+ @Nonnull
+ Collection getProblems();
+
+ /**
+ * Gets the result of the dependency resolution for the project.
+ *
+ * @return The result of the dependency resolution for the project.
+ */
+ @Nonnull
+ Optional getDependencyResolverResult();
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java
new file mode 100644
index 0000000000..1add18cb12
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java
@@ -0,0 +1,38 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The source for a project's XML model.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ProjectBuilderSource
+{
+ InputStream getInputStream() throws IOException;
+
+ String getLocation();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java
new file mode 100644
index 0000000000..a908bf19ac
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java
@@ -0,0 +1,93 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.ResolutionScope;
+import org.apache.maven.api.Session;
+
+/**
+ * Interface to manage the project during its lifecycle.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ProjectManager extends Service
+{
+ /**
+ * Returns the path to the resolved file in the local repository
+ * if the artifact has been resolved.
+ *
+ * @return the path of the resolved artifact
+ */
+ @Nonnull
+ Optional getPath( Project project );
+
+ @Nonnull
+ Collection getAttachedArtifacts( Project project );
+
+ default void attachArtifact( Session session, Project project, Path path )
+ {
+ String name = path.getFileName().toString();
+ int dot = name.lastIndexOf( '.' );
+ String ext = dot >= 1 ? name.substring( dot + 1 ) : "";
+ Artifact artifact = session.createArtifact( project.getGroupId(), project.getArtifactId(),
+ project.getVersion(), ext );
+ attachArtifact( project, artifact, path );
+ }
+
+ default void attachArtifact( Session session, Project project, String type, Path path )
+ {
+ Artifact artifact = session.createArtifact( project.getGroupId(), project.getArtifactId(),
+ project.getVersion(), null, null, type );
+ attachArtifact( project, artifact, path );
+ }
+
+ void attachArtifact( Project project, Artifact artifact, Path path );
+
+ List getCompileSourceRoots( Project project );
+
+ void addCompileSourceRoot( Project project, String sourceRoot );
+
+ List getTestCompileSourceRoots( Project project );
+
+ void addTestCompileSourceRoot( Project project, String sourceRoot );
+
+ List getRepositories( Project project );
+
+ List getResolvedDependencies( Project project, ResolutionScope scope );
+
+ Node getCollectedDependencies( Project project, ResolutionScope scope );
+
+ void setProperty( Project project, String key, String value );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java
new file mode 100644
index 0000000000..a5229f4b4f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java
@@ -0,0 +1,106 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.List;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Service used to interact with the end user.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface Prompter extends Service
+{
+ /**
+ * Prompts the user for a string.
+ *
+ * @param message the message to display to the user
+ * @return the string entered by the user
+ * @throws PrompterException if an exception occurs
+ */
+ default String prompt( String message )
+ throws PrompterException
+ {
+ return prompt( message, null, null );
+ }
+
+ /**
+ * Prompts the user for a string using a default value.
+ *
+ * @param message the message to display
+ * @param defaultReply the default reply value
+ * @return the string entered by the user
+ * @throws PrompterException if an exception occurs
+ */
+ default String prompt( String message, String defaultReply )
+ throws PrompterException
+ {
+ return prompt( message, null, defaultReply );
+ }
+
+ /**
+ * Prompts the user for a string using a list of possible values.
+ *
+ * @param message the message to display
+ * @param possibleValues the list of possible values
+ * @return the string entered by the user
+ * @throws PrompterException if an exception occurs
+ */
+ default String prompt( String message, List possibleValues )
+ throws PrompterException
+ {
+ return prompt( message, possibleValues, null );
+ }
+
+ /**
+ * Prompts the user for a string using a list of possible values and a default reply.
+ *
+ * @param message the message to display
+ * @param possibleValues the list of possible values
+ * @param defaultReply the default reply value
+ * @return the string entered by the user
+ * @throws PrompterException if an exception occurs
+ */
+ String prompt( String message, List possibleValues, String defaultReply )
+ throws PrompterException;
+
+ /**
+ * Prompts the user for a password.
+ *
+ * @param message the message to display
+ * @return the password entered by the user
+ * @throws PrompterException if an exception occurs
+ */
+ String promptForPassword( String message )
+ throws PrompterException;
+
+ /**
+ * Displays a message to the user.
+ *
+ * @param message the message to display
+ * @throws PrompterException if an exception occurs
+ */
+ void showMessage( String message )
+ throws PrompterException;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java
new file mode 100644
index 0000000000..4f892c7494
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java
@@ -0,0 +1,42 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link Prompter} service.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class PrompterException
+ extends MavenException
+{
+ /**
+ * @param message The message to give.
+ * @param e The {@link Exception}.
+ */
+ public PrompterException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java
new file mode 100644
index 0000000000..727a3e485f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java
@@ -0,0 +1,49 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.nio.file.Path;
+
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Repository;
+
+/**
+ * Factory service to create {@link LocalRepository} or {@link RemoteRepository} objects.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface RepositoryFactory extends Service
+{
+
+ @Nonnull
+ LocalRepository createLocal( @Nonnull Path path );
+
+ @Nonnull
+ RemoteRepository createRemote( @Nonnull String id, @Nonnull String url );
+
+ @Nonnull
+ RemoteRepository createRemote( @Nonnull Repository repository );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java
new file mode 100644
index 0000000000..9b0c54d555
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java
@@ -0,0 +1,33 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * @since 4.0
+ */
+@Experimental
+@Consumer
+public interface ToolchainFactory
+{
+ // TODO: implement ToolchainFactory
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
new file mode 100644
index 0000000000..d5c6c5779d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
@@ -0,0 +1,82 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Toolchain;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service to manage {@link Toolchain}s.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ToolchainManager extends Service
+{
+
+ /**
+ *
+ * @param session
+ * @param type
+ * @param requirements
+ * @return the selected {@link Toolchain}s
+ * @throws ToolchainManagerException if an exception occurs
+ */
+ @Nonnull
+ List getToolchains( @Nonnull Session session, String type, Map requirements );
+
+ /**
+ *
+ * @param session
+ * @param type
+ * @return the selected {@link Toolchain}
+ * @throws ToolchainManagerException if an exception occurs
+ */
+ @Nonnull
+ Optional getToolchainFromBuildContext( @Nonnull Session session, String type )
+ throws ToolchainManagerException;
+
+ /**
+ *
+ * @param session
+ * @param type
+ * @return the selected {@link Toolchain}s
+ * @throws ToolchainManagerException if an exception occurs
+ */
+ @Nonnull
+ List getToolchainsForType( @Nonnull Session session, String type )
+ throws ToolchainManagerException;
+
+ /**
+ *
+ * @param session
+ * @param toolchain
+ * @throws ToolchainManagerException if an exception occurs
+ */
+ void storeToolchainToBuildContext( @Nonnull Session session, Toolchain toolchain )
+ throws ToolchainManagerException;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
new file mode 100644
index 0000000000..2c8a2bd8fe
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
@@ -0,0 +1,42 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link ToolchainManager}.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class ToolchainManagerException
+ extends MavenException
+{
+ /**
+ * @param message The message to give.
+ * @param e The {@link Exception}.
+ */
+ public ToolchainManagerException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java
new file mode 100644
index 0000000000..21482ba40b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java
@@ -0,0 +1,47 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Access to {@link Type} registry.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface TypeRegistry extends Service
+{
+
+ /**
+ * Obtain the {@link Type} from the specified {@code id}.
+ * If no type is known for {@code id}, the registry will
+ * create a custom {@code Type} for it.
+ *
+ * @param id the id of the type to retrieve
+ * @return the type
+ */
+ @Nonnull
+ Type getType( @Nonnull String id );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java
new file mode 100644
index 0000000000..ed5e69ba75
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java
@@ -0,0 +1,62 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.Service;
+import org.apache.maven.api.Version;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service interface to parse {@link Version} and {@link VersionRange}.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface VersionParser extends Service
+{
+ /**
+ * Parses the specified version string, for example "1.0".
+ *
+ * @param version The version string to parse, must not be {@code null}.
+ * @return The parsed version, never {@code null}.
+ * @throws VersionParserException If the string violates the syntax rules of this scheme.
+ * @see org.apache.maven.api.Session#parseVersion(String)
+ */
+ @Nonnull
+ Version parseVersion( @Nonnull String version );
+
+ /**
+ * Parses the specified version range specification, for example "[1.0,2.0)".
+ *
+ * @param range The range specification to parse, must not be {@code null}.
+ * @return The parsed version range, never {@code null}.
+ * @throws VersionParserException If the range specification violates the syntax rules of this scheme.
+ */
+ @Nonnull
+ VersionRange parseVersionRange( @Nonnull String range );
+
+ /**
+ * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not.
+ */
+ boolean isSnapshot( @Nonnull String version );
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java
new file mode 100644
index 0000000000..f0c4481132
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java
@@ -0,0 +1,42 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class thrown by {@link VersionParser}.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class VersionParserException
+ extends MavenException
+{
+ /**
+ * @param message The message to give.
+ * @param e The {@link Exception}.
+ */
+ public VersionParserException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java
new file mode 100644
index 0000000000..8de030ff70
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java
@@ -0,0 +1,34 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.model.Model;
+
+/**
+ * Reads or writes a {@link Model} using XML.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ModelXmlFactory extends XmlFactory
+{
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java
new file mode 100644
index 0000000000..0d6672ae94
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java
@@ -0,0 +1,34 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.settings.Settings;
+
+/**
+ * Reads and writes a {@link Settings} object to/from XML.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface SettingsXmlFactory extends XmlFactory
+{
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java
new file mode 100644
index 0000000000..854cb97913
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java
@@ -0,0 +1,34 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+
+/**
+ * Reads and writes a {@link PersistedToolchains} object to/from XML.
+ *
+ * @since 4.0
+ */
+@Experimental
+public interface ToolchainsXmlFactory extends XmlFactory
+{
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java
new file mode 100644
index 0000000000..651b1a5fe8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java
@@ -0,0 +1,98 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.Service;
+
+/**
+ * Generic interface to read/write objects to/from XML.
+ *
+ * @param the object type to read/write
+ * @since 4.0
+ */
+@Experimental
+public interface XmlFactory extends Service
+{
+
+ @Nonnull
+ default T read( @Nonnull Path path ) throws XmlReaderException
+ {
+ return read( path, true );
+ }
+
+ @Nonnull
+ default T read( @Nonnull Path path, boolean strict ) throws XmlReaderException
+ {
+ return read( XmlReaderRequest.builder().path( path ).strict( strict ).build() );
+ }
+
+ @Nonnull
+ default T read( @Nonnull InputStream input ) throws XmlReaderException
+ {
+ return read( input, true );
+ }
+
+ @Nonnull
+ default T read( @Nonnull InputStream input, boolean strict ) throws XmlReaderException
+ {
+ return read( XmlReaderRequest.builder().inputStream( input ).strict( strict ).build() );
+ }
+
+ @Nonnull
+ default T read( @Nonnull Reader reader ) throws XmlReaderException
+ {
+ return read( reader, true );
+ }
+
+ @Nonnull
+ default T read( @Nonnull Reader reader, boolean strict ) throws XmlReaderException
+ {
+ return read( XmlReaderRequest.builder().reader( reader ).strict( strict ).build() );
+ }
+
+ @Nonnull
+ T read( @Nonnull XmlReaderRequest request ) throws XmlReaderException;
+
+ default void write( @Nonnull T content, @Nonnull Path path ) throws XmlWriterException
+ {
+ write( XmlWriterRequest.builder().content( content ).path( path ).build() );
+ }
+
+ default void write( @Nonnull T content, @Nonnull OutputStream outputStream ) throws XmlWriterException
+ {
+ write( XmlWriterRequest.builder().content( content ).outputStream( outputStream ).build() );
+ }
+
+ default void write( @Nonnull T content, @Nonnull Writer writer ) throws XmlWriterException
+ {
+ write( XmlWriterRequest.builder().content( content ).writer( writer ).build() );
+ }
+
+ void write( @Nonnull XmlWriterRequest request ) throws XmlWriterException;
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java
new file mode 100644
index 0000000000..2cc30c0c26
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java
@@ -0,0 +1,44 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception thrown during the reading of an xml file.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class XmlReaderException
+ extends MavenException
+{
+
+ /**
+ * @param message The message for the exception.
+ * @param e The exception itself.
+ */
+ public XmlReaderException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
new file mode 100644
index 0000000000..05e4423039
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
@@ -0,0 +1,236 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+/**
+ * An XML reader request.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Immutable
+public interface XmlReaderRequest
+{
+
+ Path getPath();
+
+ URL getURL();
+
+ InputStream getInputStream();
+
+ Reader getReader();
+
+ Transformer getTransformer();
+
+ boolean isStrict();
+
+ String getModelId();
+
+ String getLocation();
+
+ boolean isAddDefaultEntities();
+
+ interface Transformer
+ {
+ /**
+ * Interpolate the value read from the xml document
+ *
+ * @param source The source value
+ * @param fieldName A description of the field being interpolated. The implementation may use this to
+ * log stuff.
+ * @return The interpolated value.
+ */
+ String transform( String source, String fieldName );
+ }
+
+ @Nonnull
+ static XmlReaderRequestBuilder builder()
+ {
+ return new XmlReaderRequestBuilder();
+ }
+
+ @NotThreadSafe
+ class XmlReaderRequestBuilder
+ {
+ Path path;
+ URL url;
+ InputStream inputStream;
+ Reader reader;
+ Transformer transformer;
+ boolean strict;
+ String modelId;
+ String location;
+ boolean addDefaultEntities = true;
+
+ public XmlReaderRequestBuilder path( Path path )
+ {
+ this.path = path;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder url( URL url )
+ {
+ this.url = url;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder inputStream( InputStream inputStream )
+ {
+ this.inputStream = inputStream;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder reader( Reader reader )
+ {
+ this.reader = reader;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder transformer( Transformer transformer )
+ {
+ this.transformer = transformer;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder strict( boolean strict )
+ {
+ this.strict = strict;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder modelId( String modelId )
+ {
+ this.modelId = modelId;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder location( String location )
+ {
+ this.location = location;
+ return this;
+ }
+
+ public XmlReaderRequestBuilder addDefaultEntities( boolean addDefaultEntities )
+ {
+ this.addDefaultEntities = addDefaultEntities;
+ return this;
+ }
+
+ public XmlReaderRequest build()
+ {
+ return new DefaultXmlReaderRequest( path, url, inputStream, reader, transformer, strict,
+ modelId, location, addDefaultEntities );
+ }
+
+ private static class DefaultXmlReaderRequest implements XmlReaderRequest
+ {
+ final Path path;
+ final URL url;
+ final InputStream inputStream;
+ final Reader reader;
+ final Transformer transformer;
+ final boolean strict;
+ final String modelId;
+ final String location;
+ final boolean addDefaultEntities;
+
+ @SuppressWarnings( "checkstyle:ParameterNumber" )
+ DefaultXmlReaderRequest( Path path, URL url, InputStream inputStream, Reader reader,
+ Transformer transformer, boolean strict,
+ String modelId, String location,
+ boolean addDefaultEntities )
+ {
+ this.path = path;
+ this.url = url;
+ this.inputStream = inputStream;
+ this.reader = reader;
+ this.transformer = transformer;
+ this.strict = strict;
+ this.modelId = modelId;
+ this.location = location;
+ this.addDefaultEntities = addDefaultEntities;
+ }
+
+ @Override
+ public Path getPath()
+ {
+ return path;
+ }
+
+ @Override
+ public URL getURL()
+ {
+ return null;
+ }
+
+ @Override
+ public InputStream getInputStream()
+ {
+ return inputStream;
+ }
+
+ public Reader getReader()
+ {
+ return reader;
+ }
+
+ @Override
+ public Transformer getTransformer()
+ {
+ return transformer;
+ }
+
+ @Override
+ public boolean isStrict()
+ {
+ return strict;
+ }
+
+ @Override
+ public String getModelId()
+ {
+ return modelId;
+ }
+
+ @Override
+ public String getLocation()
+ {
+ return location;
+ }
+
+ @Override
+ public boolean isAddDefaultEntities()
+ {
+ return addDefaultEntities;
+ }
+ }
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java
new file mode 100644
index 0000000000..099b6ea12b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java
@@ -0,0 +1,44 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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 org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception thrown during the writing of an xml file.
+ *
+ * @since 4.0
+ */
+@Experimental
+public class XmlWriterException
+ extends MavenException
+{
+
+ /**
+ * @param message The message for the exception.
+ * @param e The exception itself.
+ */
+ public XmlWriterException( String message, Exception e )
+ {
+ super( message, e );
+ }
+
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
new file mode 100644
index 0000000000..15f0319dd8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
@@ -0,0 +1,127 @@
+package org.apache.maven.api.services.xml;
+
+/*
+ * 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.OutputStream;
+import java.io.Writer;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * An XML writer request.
+ *
+ * @since 4.0
+ * @param the object type to read
+ */
+@Experimental
+public interface XmlWriterRequest
+{
+
+ Path getPath();
+
+ OutputStream getOutputStream();
+
+ Writer getWriter();
+
+ T getContent();
+
+ static XmlWriterRequestBuilder builder()
+ {
+ return new XmlWriterRequestBuilder<>();
+ }
+
+ class XmlWriterRequestBuilder
+ {
+ Path path;
+ OutputStream outputStream;
+ Writer writer;
+ T content;
+
+ public XmlWriterRequestBuilder path( Path path )
+ {
+ this.path = path;
+ return this;
+ }
+
+ public XmlWriterRequestBuilder outputStream( OutputStream outputStream )
+ {
+ this.outputStream = outputStream;
+ return this;
+ }
+
+ public XmlWriterRequestBuilder writer( Writer writer )
+ {
+ this.writer = writer;
+ return this;
+ }
+
+ public XmlWriterRequestBuilder content( T content )
+ {
+ this.content = content;
+ return this;
+ }
+
+ public XmlWriterRequest build()
+ {
+ return new DefaultXmlWriterRequest<>( path, outputStream, writer, content );
+ }
+
+ private static class DefaultXmlWriterRequest implements XmlWriterRequest
+ {
+ final Path path;
+ final OutputStream outputStream;
+ final Writer writer;
+ final T content;
+
+ DefaultXmlWriterRequest( Path path, OutputStream outputStream, Writer writer, T content )
+ {
+ this.path = path;
+ this.outputStream = outputStream;
+ this.writer = writer;
+ this.content = content;
+ }
+
+ @Override
+ public Path getPath()
+ {
+ return path;
+ }
+
+ @Override
+ public OutputStream getOutputStream()
+ {
+ return outputStream;
+ }
+
+ @Override
+ public Writer getWriter()
+ {
+ return writer;
+ }
+
+ @Override
+ public T getContent()
+ {
+ return content;
+ }
+ }
+ }
+}
diff --git a/api/maven-api-meta/pom.xml b/api/maven-api-meta/pom.xml
new file mode 100644
index 0000000000..8c4d392ad2
--- /dev/null
+++ b/api/maven-api-meta/pom.xml
@@ -0,0 +1,32 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven-api
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ maven-api-meta
+ Maven API Meta annotations
+
+
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java
new file mode 100644
index 0000000000..f8de92bb3a
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java
@@ -0,0 +1,47 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by, or extended by maven plugins or extensions.
+ * Maven plugins or extensions may provide implementations of those types which will be used by maven.
+ *
+ * A type can be marked {@link Consumer} or {@link Provider} but not both. A type is assumed to be
+ * {@link Consumer} if it is not marked either {@link Consumer} or {@link Provider}.
+ *
+ * A package can be marked {@link Provider}. In this case, all types in the package are considered
+ * to be a provider type regardless of whether they are marked {@link Consumer} or {@link Provider}.
+ *
+ * @see Provider
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( { ElementType.TYPE, ElementType.PACKAGE } )
+public @interface Consumer
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java
new file mode 100644
index 0000000000..bb706d893f
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java
@@ -0,0 +1,37 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation tags types that are part of an experimental API.
+ * Classes or methods annotated with this annotation may be changed / removed without notice.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+public @interface Experimental
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java
new file mode 100644
index 0000000000..9813f69d5b
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java
@@ -0,0 +1,39 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that a type is automatically generated.
+ *
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( ElementType.TYPE )
+public @interface Generated
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java
new file mode 100644
index 0000000000..ea8df9a069
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java
@@ -0,0 +1,43 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The {@code Immutable} annotation indicates that the object is immutable, i.e.
+ * none of its field can be changed. This also ensures that the type is
+ * {@link ThreadSafe}.
+ *
+ * @see ThreadSafe
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@ThreadSafe
+@Target( ElementType.TYPE )
+public @interface Immutable
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java
new file mode 100644
index 0000000000..0668a3bc8f
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java
@@ -0,0 +1,44 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated element must not be null.
+ *
+ * Annotated fields must not be null after construction has completed.
+ *
+ * When this annotation is applied to a method it applies to the method return value.
+ *
+ * @see Nullable
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD } )
+public @interface Nonnull
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java
new file mode 100644
index 0000000000..ae4a6286ff
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java
@@ -0,0 +1,41 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that the annotated type is not threadsafe
+ * and should only be used by a single thread.
+ *
+ * @see ThreadSafe
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( ElementType.TYPE )
+public @interface NotThreadSafe
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java
new file mode 100644
index 0000000000..e21a6de6a7
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java
@@ -0,0 +1,37 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The annotated element can be {@code null}.
+ *
+ * @see Nonnull
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+public @interface Nullable
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java
new file mode 100644
index 0000000000..ea5174def8
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java
@@ -0,0 +1,47 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by, or extended by maven itself.
+ * Maven provides implementations of those types and may inject them in plugins.
+ *
+ * A type can be marked {@link Consumer} or {@link Provider} but not both. A type is assumed to be
+ * {@link Consumer} if it is not marked either {@link Consumer} or {@link Provider}.
+ *
+ * A package can be marked {@link Provider}. In this case, all types in the package are considered
+ * to be a provider type regardless of whether they are marked {@link Consumer} or {@link Provider}.
+ *
+ * @see Consumer
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( { ElementType.TYPE, ElementType.PACKAGE } )
+public @interface Provider
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java
new file mode 100644
index 0000000000..82d7b8463b
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java
@@ -0,0 +1,42 @@
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The {@code ThreadSafe} annotation can be used to indicate a given type
+ * is thread safe. {@link Immutable} objects are automatically thread safe.
+ *
+ * @see Immutable
+ * @see NotThreadSafe
+ * @since 4.0
+ */
+@Experimental
+@Documented
+@Retention( RetentionPolicy.CLASS )
+@Target( ElementType.TYPE )
+public @interface ThreadSafe
+{
+}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java
new file mode 100644
index 0000000000..2a0d276c78
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java
@@ -0,0 +1,30 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * This package contains non-functional annotations which are
+ * used to tag various elements and help users understanding
+ * how those types should be used.
+ *
+ * @since 4.0
+ */
+@Experimental
+package org.apache.maven.api.annotations;
+
+/*
+ * 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.
+ */
+
diff --git a/api/maven-api-model/pom.xml b/api/maven-api-model/pom.xml
new file mode 100644
index 0000000000..a62c6c72b2
--- /dev/null
+++ b/api/maven-api-model/pom.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven-api
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ maven-api-model
+
+ Maven API Model
+ Maven API Model for Maven POM (Project Object Model)
+
+
+
+ org.apache.maven
+ maven-api-xml
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.2.0
+
+
+ attach-mdo
+
+ attach-artifact
+
+
+
+
+ src/main/mdo/maven.mdo
+ mdo
+
+
+
+
+
+
+
+ org.apache.maven
+ modello-plugin-velocity
+ 4.0.0-alpha-1-SNAPSHOT
+
+ 5.0.0
+
+ src/main/mdo/maven.mdo
+
+
+ src/main/mdo/model.vm
+
+
+ packageModelV4=org.apache.maven.api.model
+
+
+
+
+ modello
+
+ velocity
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ **/package-info.java
+
+
+
+
+
+
+
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/ImmutableCollections.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/ImmutableCollections.java
new file mode 100644
index 0000000000..35c98d6e7e
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/ImmutableCollections.java
@@ -0,0 +1,738 @@
+package org.apache.maven.api.model;
+
+/*
+ * 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.AbstractList;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+class ImmutableCollections
+{
+
+ private static final List> EMPTY_LIST = new AbstractImmutableList()
+ {
+ @Override
+ public Object get( int index )
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+
+ private static final Map, ?> EMPTY_MAP = new AbstractImmutableMap()
+ {
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ @Override
+ public boolean hasNext()
+ {
+ return false;
+ }
+ @Override
+ public Entry next()
+ {
+ throw new NoSuchElementException();
+ }
+ };
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+ }
+ };
+
+ static List copy( Collection collection )
+ {
+ if ( collection == null )
+ {
+ return emptyList();
+ }
+ else if ( collection instanceof AbstractImmutableList )
+ {
+ return ( List ) collection;
+ }
+ else
+ {
+ switch ( collection.size() )
+ {
+ case 0:
+ return emptyList();
+ case 1:
+ return singletonList( collection.iterator().next() );
+ case 2:
+ Iterator it = collection.iterator();
+ return new List2<>( it.next(), it.next() );
+ default:
+ return new ListN<>( collection );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static List emptyList()
+ {
+ return ( List ) EMPTY_LIST;
+ }
+
+ static List singletonList( E element )
+ {
+ return new List1<>( element );
+ }
+
+ static Map copy( Map map )
+ {
+ if ( map == null )
+ {
+ return emptyMap();
+ }
+ else if ( map instanceof AbstractImmutableMap )
+ {
+ return map;
+ }
+ else
+ {
+ switch ( map.size() )
+ {
+ case 0:
+ return emptyMap();
+ case 1:
+ Map.Entry entry = map.entrySet().iterator().next();
+ return singletonMap( entry.getKey(), entry.getValue() );
+ default:
+ return new MapN<>( map );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static Map emptyMap()
+ {
+ return ( Map ) EMPTY_MAP;
+ }
+
+ static Map singletonMap( K key, V value )
+ {
+ return new Map1<>( key, value );
+ }
+
+ static Properties copy( Properties properties )
+ {
+ if ( properties instanceof ROProperties )
+ {
+ return properties;
+ }
+ return new ROProperties( properties );
+ }
+
+ private static class List1 extends AbstractImmutableList
+ {
+ private final E element;
+
+ private List1( E element )
+ {
+ this.element = element;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ }
+
+ private static class List2 extends AbstractImmutableList
+ {
+ private final E element1;
+ private final E element2;
+
+ private List2( E element1, E element2 )
+ {
+ this.element1 = element1;
+ this.element2 = element2;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element1;
+ }
+ else if ( index == 1 )
+ {
+ return element2;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 2;
+ }
+ }
+
+ private static class ListN extends AbstractImmutableList
+ {
+ private final Object[] elements;
+
+ private ListN( Collection elements )
+ {
+ this.elements = elements.toArray();
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public E get( int index )
+ {
+ return ( E ) elements[ index ];
+ }
+
+ @Override
+ public int size()
+ {
+ return elements.length;
+ }
+ }
+
+ private abstract static class AbstractImmutableList extends AbstractList implements RandomAccess
+ {
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean addAll( Collection extends E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( UnaryOperator operator )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void sort( Comparator super E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return new Itr( index );
+ }
+
+ @Override
+ public List subList( int fromIndex, int toIndex )
+ {
+ if ( fromIndex < 0 )
+ {
+ throw new IndexOutOfBoundsException( "fromIndex = " + fromIndex );
+ }
+ if ( toIndex > size() )
+ {
+ throw new IndexOutOfBoundsException( "toIndex = " + toIndex );
+ }
+ if ( fromIndex > toIndex )
+ {
+ throw new IllegalArgumentException( "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")" );
+ }
+ return new SubList( fromIndex, toIndex );
+ }
+
+ protected IndexOutOfBoundsException outOfBounds( int index )
+ {
+ return new IndexOutOfBoundsException( "Index: " + index + ", Size: " + size() );
+ }
+
+ private class SubList extends AbstractImmutableList
+ {
+ private final int fromIndex;
+ private final int toIndex;
+
+ private SubList( int fromIndex, int toIndex )
+ {
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return AbstractImmutableList.this.get( fromIndex + index );
+ }
+
+ @Override
+ public int size()
+ {
+ return toIndex - fromIndex;
+ }
+ }
+
+ private class Itr implements ListIterator
+ {
+ int index;
+
+ private Itr( int index )
+ {
+ this.index = index;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ @Override
+ public E next()
+ {
+ return get( index++ );
+ }
+
+ @Override
+ public boolean hasPrevious()
+ {
+ return index > 0;
+ }
+
+ @Override
+ public E previous()
+ {
+ return get( --index );
+ }
+
+ @Override
+ public int nextIndex()
+ {
+ return index;
+ }
+
+ @Override
+ public int previousIndex()
+ {
+ return index - 1;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void set( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void add( E e )
+ {
+ throw uoe();
+ }
+ }
+ }
+
+ private static class ROProperties extends Properties
+ {
+ private ROProperties( Properties props )
+ {
+ super();
+ if ( props != null )
+ {
+ // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
+ for ( Map.Entry e : props.entrySet() )
+ {
+ super.put( e.getKey(), e.getValue() );
+ }
+ }
+ }
+
+ @Override
+ public Object put( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object remove( Object key )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void putAll( Map, ?> t )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( BiFunction super Object, ? super Object, ?> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object putIfAbsent( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( Object key, Object oldValue, Object newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object replace( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfAbsent( Object key, Function super Object, ?> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfPresent( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object compute( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object merge( Object key, Object value, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private static class Map1 extends AbstractImmutableMap
+ {
+ private final Map.Entry entry;
+
+ private Map1( K key, V value )
+ {
+ this.entry = new SimpleImmutableEntry<>( key, value );
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index == 0;
+ }
+
+ @Override
+ public Entry next()
+ {
+ if ( index++ == 0 )
+ {
+ return entry;
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ };
+ }
+ }
+
+ private static class MapN extends AbstractImmutableMap
+ {
+ private final Object[] entries;
+
+ private MapN( Map map )
+ {
+ entries = map != null ? map.entrySet().toArray() : new Object[0];
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index < entries.length;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public Entry next()
+ {
+ if ( index < entries.length )
+ {
+ return ( Map.Entry ) entries[index++];
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return entries.length;
+ }
+ };
+ }
+ }
+
+ private abstract static class AbstractImmutableMap extends AbstractMap
+ {
+ @Override
+ public void replaceAll( BiFunction super K, ? super V, ? extends V> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V putIfAbsent( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( K key, V oldValue, V newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V replace( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfAbsent( K key, Function super K, ? extends V> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfPresent( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V compute( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V merge( K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private abstract static class AbstractImmutableSet extends AbstractSet
+ {
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+ }
+
+ private static UnsupportedOperationException uoe()
+ {
+ return new UnsupportedOperationException();
+ }
+
+}
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java
new file mode 100644
index 0000000000..5aff705b02
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java
@@ -0,0 +1,199 @@
+package org.apache.maven.api.model;
+
+/*
+ * 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.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Class InputLocation.
+ */
+public class InputLocation
+ implements Serializable, InputLocationTracker
+{
+ private final int lineNumber;
+ private final int columnNumber;
+ private final InputSource source;
+ private final Map locations;
+
+ public InputLocation( InputSource source )
+ {
+ this.lineNumber = -1;
+ this.columnNumber = -1;
+ this.source = source;
+ this.locations = Collections.singletonMap( 0, this );
+ }
+
+ public InputLocation( int lineNumber, int columnNumber )
+ {
+ this( lineNumber, columnNumber, null, null );
+ }
+
+ public InputLocation( int lineNumber, int columnNumber, InputSource source )
+ {
+ this( lineNumber, columnNumber, source, null );
+ }
+
+ public InputLocation( int lineNumber, int columnNumber, InputSource source, Object selfLocationKey )
+ {
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ this.source = source;
+ this.locations = selfLocationKey != null
+ ? Collections.singletonMap( selfLocationKey, this ) : Collections.emptyMap();
+ }
+
+ public InputLocation( int lineNumber, int columnNumber, InputSource source, Map locations )
+ {
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ this.source = source;
+ this.locations = ImmutableCollections.copy( locations );
+ }
+
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ public int getColumnNumber()
+ {
+ return columnNumber;
+ }
+
+ public InputSource getSource()
+ {
+ return source;
+ }
+
+ public InputLocation getLocation( Object key )
+ {
+ return locations != null ? locations.get( key ) : null;
+ }
+
+ public Map getLocations()
+ {
+ return locations;
+ }
+
+ /**
+ * Method merge.
+ */
+ public static InputLocation merge( InputLocation target, InputLocation source, boolean sourceDominant )
+ {
+ if ( source == null )
+ {
+ return target;
+ }
+ else if ( target == null )
+ {
+ return source;
+ }
+
+ Map locations;
+ Map sourceLocations = source.locations;
+ Map targetLocations = target.locations;
+ if ( sourceLocations == null )
+ {
+ locations = targetLocations;
+ }
+ else if ( targetLocations == null )
+ {
+ locations = sourceLocations;
+ }
+ else
+ {
+ locations = new LinkedHashMap<>();
+ locations.putAll( sourceDominant ? targetLocations : sourceLocations );
+ locations.putAll( sourceDominant ? sourceLocations : targetLocations );
+ }
+
+ return new InputLocation( target.getLineNumber(), target.getColumnNumber(), target.getSource(), locations );
+ } //-- InputLocation merge( InputLocation, InputLocation, boolean )
+
+ /**
+ * Method merge.
+ */
+ public static InputLocation merge( InputLocation target, InputLocation source, Collection indices )
+ {
+ if ( source == null )
+ {
+ return target;
+ }
+ else if ( target == null )
+ {
+ return source;
+ }
+
+ Map locations;
+ Map sourceLocations = source.locations;
+ Map targetLocations = target.locations;
+ if ( sourceLocations == null )
+ {
+ locations = targetLocations;
+ }
+ else if ( targetLocations == null )
+ {
+ locations = sourceLocations;
+ }
+ else
+ {
+ locations = new LinkedHashMap<>();
+ for ( int index : indices )
+ {
+ InputLocation location;
+ if ( index < 0 )
+ {
+ location = sourceLocations.get( ~index );
+ }
+ else
+ {
+ location = targetLocations.get( index );
+ }
+ locations.put( locations.size(), location );
+ }
+ }
+
+ return new InputLocation( target.getLineNumber(), target.getColumnNumber(), target.getSource(), locations );
+ } //-- InputLocation merge( InputLocation, InputLocation, java.util.Collection )
+
+ /**
+ * Class StringFormatter.
+ *
+ * @version $Revision$ $Date$
+ */
+ public interface StringFormatter
+ {
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method toString.
+ */
+ String toString( InputLocation location );
+
+ }
+
+}
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java
new file mode 100644
index 0000000000..e90934813a
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java
@@ -0,0 +1,26 @@
+package org.apache.maven.api.model;
+
+/*
+ * 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.
+ */
+
+public interface InputLocationTracker
+{
+ InputLocation getLocation( Object field );
+}
+
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java
new file mode 100644
index 0000000000..34c8bf642a
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java
@@ -0,0 +1,61 @@
+package org.apache.maven.api.model;
+
+/*
+ * 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.Serializable;
+
+/**
+ * Class InputSource.
+ */
+public class InputSource
+ implements Serializable
+{
+
+ private final String modelId;
+ private final String location;
+
+ public InputSource( String modelId, String location )
+ {
+ this.modelId = modelId;
+ this.location = location;
+ }
+
+ /**
+ * Get the path/URL of the POM or {@code null} if unknown.
+ */
+ public String getLocation()
+ {
+ return this.location;
+ }
+
+ /**
+ * Get the identifier of the POM in the format {@code ::}.
+ */
+ public String getModelId()
+ {
+ return this.modelId;
+ }
+
+ @Override
+ public String toString()
+ {
+ return getModelId() + " " + getLocation();
+ }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/package-info.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java
similarity index 96%
rename from maven-model/src/main/java/org/apache/maven/model/package-info.java
rename to api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java
index 88d3fa0701..bfcdbe273c 100644
--- a/maven-model/src/main/java/org/apache/maven/model/package-info.java
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java
@@ -3,7 +3,7 @@
* Maven POM (Project Object Model) classes, generated from maven.mdo
model.
* The root class is {@link org.apache.maven.model.Model}.
*/
-package org.apache.maven.model;
+package org.apache.maven.api.model;
/*
* Licensed to the Apache Software Foundation (ASF) under one
diff --git a/api/maven-api-model/src/main/mdo/common.vm b/api/maven-api-model/src/main/mdo/common.vm
new file mode 100644
index 0000000000..3c3f29cf7a
--- /dev/null
+++ b/api/maven-api-model/src/main/mdo/common.vm
@@ -0,0 +1,31 @@
+#*
+ 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 following loop code is required in order to change the type of the
+## pomFile attribute to a java.nio.file.Path. Modello does not support this
+## type and loading a model with such a type would fail the modello validation.
+##
+#foreach ( $field in $model.getClass("Model", $version).allFields )
+ #if ( $field.name == "pomFile" )
+ #set ( $dummy = $field.setType("java.nio.file.Path") )
+ #end
+#end
+#set ( $locationTracking = true )
+#
\ No newline at end of file
diff --git a/maven-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
similarity index 84%
rename from maven-model/src/main/mdo/maven.mdo
rename to api/maven-api-model/src/main/mdo/maven.mdo
index b669128b25..7bd835d098 100644
--- a/maven-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -66,18 +66,26 @@
-
+
Model
ModelBase
<project> element is the root of the descriptor.
+ The {@code } element is the root of the descriptor.
The following table lists all of the possible child elements.
]]>
3.0.0+
+
+ pomFile
+ 5.0.0+
+ false
+ Originating POM file
+ DOM
+
+
@@ -117,7 +125,7 @@
org.apache.maven).
+ projects with a similar name (eg. {@code org.apache.maven}).
]]>
String
@@ -144,10 +152,10 @@
4.0.0+
jar
- war
- ear
- pom
.
+ The type of artifact this project produces, for example {@code jar}
+ {@code war}
+ {@code ear}
+ {@code pom}.
Plugins can create their own packaging, and
therefore their own packaging types,
so this list does not contain all possible types.
@@ -185,7 +193,7 @@
Default value is : parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
- project's child.project.url.inherit.append.path="false"
+ project's {@code child.project.url.inherit.append.path="false"}
]]>
String
@@ -196,9 +204,9 @@
String for technical reasons, the semantic type is actually
- Boolean
- Default value is : true
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}
+ Default value is : {@code true}
Since : Maven 3.6.1
]]>
@@ -229,7 +237,7 @@
license element, which
+ Each license is described by a {@code license} element, which
is then described by additional elements.
Projects should only list the license(s) that applies to the project
and not the licenses that apply to dependencies.
@@ -353,19 +361,9 @@
- 4.0.0+
+ 4.0.0/4.1.0
groupId:artifactId:packaging:version
+ * @return the model id as {@code groupId:artifactId:packaging:version}
*/
public String getId()
{
@@ -416,22 +419,62 @@
{
return getId();
}
- ]]>
-
-
-
- 4.0.0+
-
-
+
+
+
+ 5.0.0+
+
+
@@ -439,12 +482,12 @@
-
+
ModelBase
3.0.0+
Model and the Profile
objects.
+ Base class for the {@code Model} and the {@code Profile} objects.
]]>
@@ -476,7 +519,7 @@
<name>value</name>.
+ The format is {@code value }.
]]>
Properties
@@ -537,16 +580,6 @@
*
-
- reports
- 4.0.0+
-
- Deprecated. Now ignored by Maven.
- ]]>
-
- DOM
-
reporting
4.0.0+
@@ -554,7 +587,7 @@
mvn site.
+ These reports will be run when a user executes {@code mvn site}.
All of the reports will be included in the navigation bar for browsing.
]]>
@@ -564,7 +597,7 @@
-
+
PluginContainer
3.0.0+
Contains the plugins informations for the project.
@@ -584,10 +617,10 @@
4.0.0+
pluginMap;
+ Map pluginMap;
/**
- * Reset the pluginsMap
field to null
+ * Reset the {@code pluginsMap} field to {@code null}
*/
public synchronized void flushPluginMap()
{
@@ -595,17 +628,17 @@
}
/**
- * @return a Map of plugins field with Plugins#getKey()
as key
+ * @return a Map of plugins field with {@code Plugins#getKey()} as key
* @see org.apache.maven.model.Plugin#getKey()
*/
- public synchronized java.util.Map getPluginsAsMap()
+ public synchronized Map getPluginsAsMap()
{
if ( pluginMap == null )
{
pluginMap = new java.util.LinkedHashMap();
- if ( plugins != null )
+ if ( getPlugins() != null )
{
- for ( java.util.Iterator it = plugins.iterator(); it.hasNext(); )
+ for ( java.util.Iterator it = getPlugins().iterator(); it.hasNext(); )
{
Plugin plugin = (Plugin) it.next();
pluginMap.put( plugin.getKey(), plugin );
@@ -664,7 +697,7 @@
This element describes all of the classpath resources such as properties
files associated with a project. These resources are often included in the final
package.
- The default value is src/main/resources
.]]>
+ The default value is {@code src/main/resources}.]]>
Resource
@@ -677,7 +710,7 @@
src/test/resources
.]]>
+ The default value is {@code src/test/resources}.]]>
Resource
@@ -689,7 +722,7 @@
4.0.0+
target.]]>
+ The default value is {@code target}.]]>
String
@@ -700,7 +733,7 @@
${artifactId}-${version}.
+ The default value is {@code ${artifactId}-${version}}.
]]>
String
@@ -722,7 +755,7 @@
BuildBase
<build> element contains informations required to build the project.
+ The {@code } element contains informations required to build the project.
Default values are defined in Super POM.
]]>
@@ -735,7 +768,7 @@
This element specifies a directory containing the source of the project. The
generated build system will compile the sources from this directory when the project is
built. The path given is relative to the project descriptor.
- The default value is src/main/java
.]]>
+ The default value is {@code src/main/java}.]]>
String
@@ -748,7 +781,7 @@
project. This directory is meant to be different from the sourceDirectory, in that its
contents will be copied to the output directory in most cases (since scripts are
interpreted rather than compiled).
- The default value is src/main/scripts
.]]>
+ The default value is {@code src/main/scripts}.]]>
String
@@ -760,7 +793,7 @@
This element specifies a directory containing the unit test source of the
project. The generated build system will compile these directories when the project is
being tested. The path given is relative to the project descriptor.
- The default value is src/test/java
.]]>
+ The default value is {@code src/test/java}.]]>
String
@@ -769,7 +802,7 @@
4.0.0+
target/classes.]]>
+ The default value is {@code target/classes}.]]>
String
@@ -778,7 +811,7 @@
4.0.0+
target/test-classes.]]>
+ The default value is {@code target/test-classes}.]]>
String
@@ -793,12 +826,12 @@
-
+
CiManagement
4.0.0+
<CiManagement> element contains informations required to the
+ The {@code } element contains informations required to the
continuous integration system of the project.
]]>
@@ -808,7 +841,7 @@
4.0.0+
continuum.
+ The name of the continuous integration system, e.g. {@code continuum}.
]]>
String
@@ -832,7 +865,7 @@
-
+
Notifier
Configures one method for notifying users/developers when a build breaks.
4.0.0+
@@ -894,7 +927,7 @@
-
+
Contributor
Description of a person who has contributed to the project, but who does not have
commit privileges. Usually, these contributions come in the form of patches submitted.
@@ -939,7 +972,7 @@
role element, the body of which is a role name. This can also be used to
+ {@code role} element, the body of which is a role name. This can also be used to
describe the contribution.
]]>
@@ -972,12 +1005,12 @@
-
+
Dependency
3.0.0+
<dependency> element contains information about a dependency
+ The {@code } element contains information about a dependency
of the project.
]]>
@@ -989,7 +1022,7 @@
org.apache.maven.
+ {@code org.apache.maven}.
]]>
String
@@ -1001,7 +1034,7 @@
maven-artifact.
+ {@code maven-artifact}.
]]>
String
@@ -1011,7 +1044,7 @@
3.0.0+
3.2.1. In Maven 2, this can also be
+ The version of the dependency, e.g. {@code 3.2.1}. In Maven 2, this can also be
specified as a range of versions.
]]>
@@ -1023,8 +1056,8 @@
jar, war
, ejb-client
- and test-jar
: see default
+ Some examples are {@code jar}, {@code war}, {@code ejb-client}
+ and {@code test-jar}: see default
artifact handlers for a list. New types can be defined by extensions, so this is not a complete list.
]]>
@@ -1039,11 +1072,11 @@
The classifier of the dependency. It is appended to
the filename after the version. This allows:
- referring to attached artifact, for example sources
and javadoc
:
+ referring to attached artifact, for example {@code sources} and {@code javadoc}:
see default artifact handlers for a list,
distinguishing two artifacts
that belong to the same POM but were built differently.
- For example, jdk14
and jdk15
.
+ For example, {@code jdk14} and {@code jdk15}.
]]>
@@ -1055,13 +1088,13 @@
4.0.0+
compile, runtime
,
- test
, system
, and provided
. Used to
+ The scope of the dependency - {@code compile}, {@code runtime},
+ {@code test}, {@code system}, and {@code provided}. Used to
calculate the various classpaths used for compilation, testing, and so on.
It also assists in determining which artifacts to include in a distribution of
this project. For more information, see
the
- dependency mechanism . The default scope is compile
.
+ dependency mechanism. The default scope is {@code compile}.
]]>
String
@@ -1081,7 +1114,7 @@
for this dependency.
Requires an absolute path for the value, not relative.
Use a property that gives the machine specific absolute path,
- e.g. ${java.home}
.
+ e.g. {@code ${java.home}}.
]]>
String
@@ -1104,8 +1137,8 @@
Indicates the dependency is optional for use of this library. While the
version of the dependency will be taken into account for dependency calculation if the
library is used elsewhere, it will not be passed on transitively. Note: While the type
- of this field is String
for technical reasons, the semantic type is actually
- Boolean
. Default value is false
.
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code false}.
]]>
String
@@ -1118,20 +1151,34 @@
+
+
+
+ 4.0.0/4.1.0
+
+
+
+
+
+ 4.0.0+
+
+
@@ -1140,27 +1187,19 @@
4.0.0+
groupId:artifactId:type
+ * @return the management key as {@code groupId:artifactId:type}
*/
public String getManagementKey()
{
if ( managementKey == null )
{
- managementKey = groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" );
+ managementKey = getGroupId() + ":" + getArtifactId() + ":" + getType() + ( getClassifier() != null ? ":" + getClassifier() : "" );
}
return managementKey;
}
-
- /**
- * Clears the management key in case one field has been modified.
- */
- public void clearManagementKey()
- {
- managementKey = null;
- }
]]>
@@ -1180,12 +1219,12 @@
-
+
Exclusion
4.0.0+
<exclusion> element contains informations required to exclude
+ The {@code } element contains informations required to exclude
an artifact to the project.
]]>
@@ -1206,7 +1245,7 @@
-
+
IssueManagement
Information about the issue tracking (or bug tracking) system used to manage this
project.
@@ -1226,7 +1265,7 @@
-
+
DistributionManagement
4.0.0+
This elements describes all that pertains to distribution for a project. It is
@@ -1247,7 +1286,7 @@
repository element.
+ {@code repository} element.
]]>
@@ -1268,7 +1307,7 @@
url.
+ referred to the homepage given by {@code url}.
This is given to assist in locating artifacts that are not in the repository due to
licensing restrictions.
]]>
@@ -1291,11 +1330,11 @@
none (default),
- converted
(repository manager converted this from an Maven 1 POM),
- partner
- (directly synced from a partner Maven 2 repository), deployed
(was deployed from a Maven 2
- instance), verified
(has been hand verified as correct and final).
+ tools placing it in the reposiory. Valid values are: {@code none} (default),
+ {@code converted} (repository manager converted this from an Maven 1 POM),
+ {@code partner}
+ (directly synced from a partner Maven 2 repository), {@code deployed} (was deployed from a Maven 2
+ instance), {@code verified} (has been hand verified as correct and final).
]]>
false
@@ -1303,7 +1342,7 @@
-
+
License
Describes the licenses for this project. This is used to generate the license
page of the project's web site, as well as being taken into consideration in other reporting
@@ -1347,7 +1386,7 @@
-
+
MailingList
3.0.0+
This element describes all of the mailing lists associated with a project. The
@@ -1370,7 +1409,7 @@
mailto: link will automatically be created
+ {@code mailto:} link will automatically be created
when the documentation is created.
]]>
@@ -1383,7 +1422,7 @@
mailto: link will automatically be created
+ {@code mailto:} link will automatically be created
when the documentation is created.
]]>
@@ -1396,7 +1435,7 @@
mailto: link will automatically be created
+ {@code mailto:} link will automatically be created
when the documentation is created.
]]>
@@ -1422,7 +1461,7 @@
and maybe even a specific element for the user and scm mailing lists. Then leave the more
lose structure for any other type of mailing list.
-
+
Organization
Specifies the organization that produces this project.
3.0.0+
@@ -1441,7 +1480,7 @@
-
+
PatternSet
3.0.0+
Definition of include or exclude patterns.
@@ -1451,7 +1490,7 @@
3.0.0+
**/*.xml.
+ A list of patterns to include, e.g. {@code **/*.xml}.
]]>
@@ -1464,7 +1503,7 @@
3.0.0+
**/*.xml
+ A list of patterns to exclude, e.g. {@code **/*.xml}
]]>
@@ -1509,12 +1548,12 @@
-
+
Parent
4.0.0+
<parent> element contains information required to locate the parent project from which
+ The {@code } element contains information required to locate the parent project from which
this project will inherit from.
Note: The children of this element are not interpolated and must be given as literal values.
]]>
@@ -1545,11 +1584,11 @@
4.0.0+
pom.xml file within the check out.
- If not specified, it defaults to ../pom.xml
.
+ The relative path of the parent {@code pom.xml} file within the check out.
+ If not specified, it defaults to {@code ../pom.xml}.
Maven looks for the parent POM first in this location on
the filesystem, then the local repository, and lastly in the remote repo.
- relativePath
allows you to select a different location,
+ {@code relativePath} allows you to select a different location,
for example when your structure is flat, or deeper without an intermediate parent POM.
However, the group ID, artifact ID and version are still required,
and must match the file in the location given or it will revert to the repository for the POM.
@@ -1568,7 +1607,7 @@
groupId:artifactId:version
+ * @return the id as {@code groupId:artifactId:version}
*/
public String getId()
{
@@ -1596,12 +1635,12 @@
-
+
Scm
4.0.0+
<scm> element contains informations required to the SCM
+ The {@code } element contains informations required to the SCM
(Source Control Management) of the project.
]]>
@@ -1618,7 +1657,7 @@
and list of supported SCMs .
This connection is read-only.
Default value is : parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
- scm's child.scm.connection.inherit.append.path="false"
+ scm's {@code child.scm.connection.inherit.append.path="false"}
]]>
String
@@ -1628,10 +1667,10 @@
4.0.0+
connection, but for developers, i.e. this scm connection
+ Just like {@code connection}, but for developers, i.e. this scm connection
will not be read only.
Default value is : parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
- scm's child.scm.developerConnection.inherit.append.path="false"
+ scm's {@code child.scm.developerConnection.inherit.append.path="false"}
]]>
String
@@ -1650,7 +1689,7 @@
Default value is : parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
- scm's child.scm.url.inherit.append.path="false"
+ scm's {@code child.scm.url.inherit.append.path="false"}
]]>
String
@@ -1661,9 +1700,9 @@
String for technical reasons, the semantic type is actually
- Boolean
- Default value is : true
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}
+ Default value is : {@code true}
Since : Maven 3.6.1
]]>
@@ -1675,9 +1714,9 @@
String for technical reasons, the semantic type is actually
- Boolean
- Default value is : true
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}
+ Default value is : {@code true}
Since : Maven 3.6.1
]]>
@@ -1689,9 +1728,9 @@
String for technical reasons, the semantic type is actually
- Boolean
- Default value is : true
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}
+ Default value is : {@code true}
Since : Maven 3.6.1
]]>
@@ -1706,32 +1745,17 @@
public boolean isChildScmConnectionInheritAppendPath()
{
- return ( childScmConnectionInheritAppendPath != null ) ? Boolean.parseBoolean( childScmConnectionInheritAppendPath ) : true;
- }
-
- public void setChildScmConnectionInheritAppendPath( boolean childScmConnectionInheritAppendPath )
- {
- this.childScmConnectionInheritAppendPath = String.valueOf( childScmConnectionInheritAppendPath );
+ return ( getChildScmConnectionInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmConnectionInheritAppendPath() ) : true;
}
public boolean isChildScmDeveloperConnectionInheritAppendPath()
{
- return ( childScmDeveloperConnectionInheritAppendPath != null ) ? Boolean.parseBoolean( childScmDeveloperConnectionInheritAppendPath ) : true;
- }
-
- public void setChildScmDeveloperConnectionInheritAppendPath( boolean childScmDeveloperConnectionInheritAppendPath )
- {
- this.childScmDeveloperConnectionInheritAppendPath = String.valueOf( childScmDeveloperConnectionInheritAppendPath );
+ return ( getChildScmDeveloperConnectionInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmDeveloperConnectionInheritAppendPath() ) : true;
}
public boolean isChildScmUrlInheritAppendPath()
{
- return ( childScmUrlInheritAppendPath != null ) ? Boolean.parseBoolean( childScmUrlInheritAppendPath ) : true;
- }
-
- public void setChildScmUrlInheritAppendPath( boolean childScmUrlInheritAppendPath )
- {
- this.childScmUrlInheritAppendPath = String.valueOf( childScmUrlInheritAppendPath );
+ return ( getChildScmUrlInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmUrlInheritAppendPath() ) : true;
}
]]>
@@ -1783,10 +1807,10 @@
${project.build.outputDirectory}).
+ directory (i.e. {@code ${project.build.outputDirectory}}).
For example, if you want that resource to appear in a specific package
- (org.apache.maven.messages
), you must specify this
- element with this value: org/apache/maven/messages
.
+ ({@code org.apache.maven.messages}), you must specify this
+ element with this value: {@code org/apache/maven/messages}.
This is not required if you simply put the resources in that directory
structure at the source, however.
]]>
@@ -1799,10 +1823,10 @@
properties element and from the
- properties in the files listed in the filters
element. Note: While the type
- of this field is String
for technical reasons, the semantic type is actually
- Boolean
. Default value is false
.
+ The values are taken from the {@code properties} element and from the
+ properties in the files listed in the {@code filters} element. Note: While the type
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code false}.
]]>
String
@@ -1827,26 +1851,28 @@
4.0.0+
+
+
+
+ 4.0.0/4.1.0
+
+
+
+
+
+ 4.0.0+
+
+
-
+
RepositoryBase
4.0.0+
A repository contains the information needed for establishing connections with
@@ -1873,7 +1899,7 @@
settings.xml file, for example. Furthermore, the identifier is
+ to configuration in the {@code settings.xml} file, for example. Furthermore, the identifier is
used during POM inheritance and profile injection to detect repositories that should be merged.
]]>
@@ -1891,7 +1917,7 @@
true
protocol://hostname/path.
+ The url of the repository, in the form {@code protocol://hostname/path}.
]]>
String
@@ -1902,7 +1928,7 @@
legacy or default
.
+ can be {@code legacy} or {@code default}.
]]>
String
@@ -1955,7 +1981,7 @@
-
+
RepositoryPolicy
4.0.0+
Download policy.
@@ -1966,8 +1992,8 @@
String for technical reasons, the semantic type is actually
- Boolean
. Default value is true
.
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code true}.
]]>
String
@@ -1978,12 +2004,12 @@
always,
- daily
+ {@code always,}
+ {@code daily}
(default),
- interval:XXX
+ {@code interval:XXX}
(in minutes) or
- never
+ {@code never}
(only if it doesn't exist locally).
]]>
@@ -1995,10 +2021,10 @@
ignore,
- fail
+ {@code ignore},
+ {@code fail}
(default for Maven 4 and above) or
- warn
+ {@code warn}
(default for Maven 2 and 3)
]]>
@@ -2010,15 +2036,21 @@
4.0.0+
+
+
+
+ 4.0.0/4.1.0
+
+
@@ -2028,7 +2060,7 @@
-
+
Site
4.0.0+
Contains the information needed for deploying websites.
@@ -2039,7 +2071,7 @@
settings.xml file, for example.
+ site to configuration in the {@code settings.xml} file, for example.
]]>
String
@@ -2055,9 +2087,9 @@
4.0.0+
protocol://hostname/path.
+ The url of the location where website is deployed, in the form {@code protocol://hostname/path}.
Default value is : parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
- site's child.site.url.inherit.append.path="false"
+ site's {@code child.site.url.inherit.append.path="false"}
]]>
String
@@ -2068,9 +2100,9 @@
String for technical reasons, the semantic type is actually
- Boolean
- Default value is : true
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}
+ Default value is : {@code true}
Since : Maven 3.6.1
]]>
@@ -2085,12 +2117,7 @@
public boolean isChildSiteUrlInheritAppendPath()
{
- return ( childSiteUrlInheritAppendPath != null ) ? Boolean.parseBoolean( childSiteUrlInheritAppendPath ) : true;
- }
-
- public void setChildSiteUrlInheritAppendPath( boolean childSiteUrlInheritAppendPath )
- {
- this.childSiteUrlInheritAppendPath = String.valueOf( childSiteUrlInheritAppendPath );
+ return ( getChildSiteUrlInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildSiteUrlInheritAppendPath() ) : true;
}
]]>
@@ -2099,7 +2126,7 @@
-
+
ConfigurationContainer
4.0.0+
Contains the configuration information of the container like Plugin.
@@ -2110,8 +2137,8 @@
String for technical reasons, the semantic type is actually
- Boolean
. Default value is true
.
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code true}.
]]>
String
@@ -2121,12 +2148,12 @@
The configuration as DOM object.
By default, every element content is trimmed, but starting with Maven 3.1.0, you can add
- xml:space="preserve"
to elements you want to preserve whitespace.
- You can control how child POMs inherit configuration from parent POMs by adding combine.children
- or combine.self
attributes to the children of the configuration element:
+ {@code xml:space="preserve"} to elements you want to preserve whitespace.
+ You can control how child POMs inherit configuration from parent POMs by adding {@code combine.children}
+ or {@code combine.self} attributes to the children of the configuration element:
- combine.children
: available values are merge
(default) and append
,
- combine.self
: available values are merge
(default) and override
.
+ {@code combine.children}: available values are {@code merge} (default) and {@code append},
+ {@code combine.self}: available values are {@code merge} (default) and {@code override}.
See POM Reference documentation and
Xpp3DomUtils
@@ -2144,25 +2171,9 @@
@@ -2174,7 +2185,7 @@
ConfigurationContainer
<plugin> element contains informations required for a plugin.
+ The {@code } element contains informations required for a plugin.
]]>
@@ -2206,8 +2217,8 @@
String for technical reasons, the semantic type is actually
- Boolean
. Default value is false
.
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code false}.
]]>
@@ -2231,16 +2242,6 @@
*
-
- goals
- 4.0.0+
-
- Deprecated. Unused by Maven.
- ]]>
-
- DOM
-
@@ -2249,26 +2250,37 @@
+
+
+
+ 4.0.0/4.1.0
+
+
+
+
+
+ 4.0.0+
+
+ executionMap = null;
/**
- * Reset the executionMap
field to null
+ * Reset the {@code executionMap} field to {@code null}
*/
public void flushExecutionMap()
{
this.executionMap = null;
}
-
/**
- * @return a Map of executions field with PluginExecution#getId()
as key
+ * @return a Map of executions field with {@code PluginExecution#getId()} as key
* @see org.apache.maven.model.PluginExecution#getId()
*/
public java.util.Map getExecutionsAsMap()
@@ -2276,22 +2288,16 @@
if ( executionMap == null )
{
executionMap = new java.util.LinkedHashMap();
- if ( getExecutions() != null )
+ for ( java.util.Iterator i = getExecutions().iterator(); i.hasNext(); )
{
- for ( java.util.Iterator i = getExecutions().iterator(); i.hasNext(); )
+ PluginExecution exec = (PluginExecution) i.next();
+ if ( executionMap.containsKey( exec.getId() ) )
{
- PluginExecution exec = (PluginExecution) i.next();
-
- if ( executionMap.containsKey( exec.getId() ) )
- {
- throw new IllegalStateException( "You cannot have two plugin executions with the same (or missing) elements.\nOffending execution\n\nId: \'" + exec.getId() + "\'\nPlugin:\'" + getKey() + "\'\n\n" );
- }
-
- executionMap.put( exec.getId(), exec );
+ throw new IllegalStateException( "You cannot have two plugin executions with the same (or missing) elements.\nOffending execution\n\nId: \'" + exec.getId() + "\'\nPlugin:\'" + getKey() + "\'\n\n" );
}
+ executionMap.put( exec.getId(), exec );
}
}
-
return executionMap;
}
@@ -2314,17 +2320,17 @@
}
/**
- * @return the key of the plugin, ie groupId:artifactId
+ * @return the key of the plugin, ie {@code groupId:artifactId}
*/
public String getKey()
{
- return constructKey( groupId, artifactId );
+ return constructKey( getGroupId(), getArtifactId() );
}
/**
* @param groupId The group ID of the plugin in the repository
* @param artifactId The artifact ID of the reporting plugin in the repository
- * @return the key of the plugin, ie groupId:artifactId
+ * @return the key of the plugin, ie {@code groupId:artifactId}
*/
public static String constructKey( String groupId, String artifactId )
{
@@ -2372,7 +2378,7 @@
ConfigurationContainer
<execution>
element contains informations required for the
+ The {@code } element contains informations required for the
execution of a plugin.
]]>
@@ -2432,7 +2438,7 @@
-
+
DependencyManagement
4.0.0+
Section for management of default dependency information for use in a group of
@@ -2458,7 +2464,7 @@
Section for management of default plugin information for use in a group of POMs.
-
+
Reporting
4.0.0+
Section for management of reports and their configuration.
@@ -2471,8 +2477,8 @@
String for technical reasons, the semantic type is actually
- Boolean
. Default value is false
.
+ of this field is {@code String} for technical reasons, the semantic type is actually
+ {@code Boolean}. Default value is {@code false}.
]]>
@@ -2483,7 +2489,7 @@
${project.build.directory}/site.
+ {@code ${project.build.directory}/site}.
]]>
@@ -2505,45 +2511,21 @@
+
+
+
+ 4.0.0/4.1.0
+
+ reportPluginMap;
-
- /**
- * Reset the reportPluginMap
field to null
- */
- public synchronized void flushReportPluginMap()
- {
- this.reportPluginMap = null;
- }
-
- /**
- * @return a Map of plugins field with ReportPlugin#getKey()
as key
- * @see org.apache.maven.model.ReportPlugin#getKey()
- */
- public synchronized java.util.Map getReportPluginsAsMap()
- {
- if ( reportPluginMap == null )
- {
- reportPluginMap = new java.util.LinkedHashMap();
- if ( getPlugins() != null )
- {
- for ( java.util.Iterator it = getPlugins().iterator(); it.hasNext(); )
- {
- ReportPlugin reportPlugin = (ReportPlugin) it.next();
- reportPluginMap.put( reportPlugin.getKey(), reportPlugin );
- }
- }
- }
-
- return reportPluginMap;
- }
]]>
@@ -2588,7 +2570,35 @@
- 4.0.0+
+ 4.0.0/4.1.0
+
+
+
+
+
+ 5.0.0+
-
+
Activation
4.0.0+
The conditions within the build runtime environment which will trigger the
@@ -2644,9 +2654,9 @@
1.4 only activates on JDKs versioned 1.4,
- while !1.4
matches any JDK that is not version 1.4. Ranges are supported too:
- [1.5,)
activates when the JDK is 1.5 minimum.
+ For example, {@code 1.4} only activates on JDKs versioned 1.4,
+ while {@code !1.4} matches any JDK that is not version 1.4. Ranges are supported too:
+ {@code [1.5,)} activates when the JDK is 1.5 minimum.
]]>
@@ -2690,7 +2700,7 @@
-->
-
+
ActivationProperty
4.0.0+
This is the property specification used to activate a profile. If the value field
@@ -2712,7 +2722,7 @@
-
+
ActivationOS
4.0.0+
This is an activator which will detect an operating system's attributes in order
@@ -2725,7 +2735,7 @@
${os.name} Java property, such as Windows XP
.
+ of the {@code ${os.name}} Java property, such as {@code Windows XP}.
]]>
@@ -2736,7 +2746,7 @@
windows or unix
.
+ {@code windows} or {@code unix}.
]]>
@@ -2756,14 +2766,14 @@
-
+
ActivationFile
4.0.0+
- missing value
+ exists will test for the existence of the file and if it is
+ activated. On the other hand, {@code exists} will test for the existence of the file and if it is
there, the profile will be activated.
- Variable interpolation for these file specifications is limited to ${basedir}
,
+ Variable interpolation for these file specifications is limited to {@code ${basedir}},
System properties and request properties.]]>
@@ -2812,7 +2822,7 @@
ConfigurationContainer
<plugin> element in <reporting><plugins>
contains informations required for a report plugin.
+ The {@code } element in {@code } contains informations required for a report plugin.
]]>
@@ -2836,8 +2846,8 @@
4.0.0+
build/plugins then in build/pluginManagement
.
+ The version of the reporting plugin to be used. Starting with Maven 3, if no version is defined explicitely,
+ version is searched in {@code build/plugins} then in {@code build/pluginManagement}.
]]>
String
@@ -2848,7 +2858,7 @@
execution in the build.
+ configuration. This is the reporting parallel to an {@code execution} in the build.
]]>
@@ -2865,7 +2875,7 @@
private java.util.Map reportSetMap = null;
/**
- * Reset the reportSetMap
field to null
+ * Reset the {@code reportSetMap} field to {@code null}
*/
public void flushReportSetMap()
{
@@ -2873,7 +2883,7 @@
}
/**
- * @return a Map of reportSets field with ReportSet#getId()
as key
+ * @return a Map of reportSets field with {@code ReportSet#getId()} as key
* @see org.apache.maven.model.ReportSet#getId()
*/
public java.util.Map getReportSetsAsMap()
@@ -2895,17 +2905,17 @@
}
/**
- * @return the key of the report plugin, ie groupId:artifactId
+ * @return the key of the report plugin, ie {@code groupId:artifactId}
*/
public String getKey()
{
- return constructKey( groupId, artifactId );
+ return constructKey( getGroupId(), getArtifactId() );
}
/**
* @param groupId The group ID of the plugin in the repository
* @param artifactId The artifact ID of the reporting plugin in the repository
- * @return the key of the report plugin, ie groupId:artifactId
+ * @return the key of the report plugin, ie {@code groupId:artifactId}
*/
public static String constructKey( String groupId, String artifactId )
{
@@ -2916,7 +2926,7 @@
-
+
ReportSet
4.0.0+
ConfigurationContainer
@@ -2957,7 +2967,7 @@
-
+
Prerequisites
4.0.0+
Describes the prerequisites a project can have.
@@ -2968,19 +2978,19 @@
String
2.0
maven-plugin), the minimum version of
+ For a plugin project (packaging is {@code maven-plugin}), the minimum version of
Maven required to use the resulting plugin.
In Maven 2, this was also specifying the minimum version of Maven required to build a
project, but this usage is deprecated in Maven 3 and not checked any more: use
the Maven Enforcer Plugin's
- requireMavenVersion
rule instead.
+ {@code requireMavenVersion} rule instead.
]]>
false
-
+
Relocation
4.0.0+
Describes where an artifact has moved to. If any of the values are omitted, it is
@@ -3012,7 +3022,7 @@
-
+
Extension
4.0.0+
Describes a build extension to utilise.
@@ -3096,7 +3106,7 @@
-
+
InputLocation
4.0.0+
@@ -3118,7 +3128,7 @@
-
+
InputSource
4.0.0+
diff --git a/api/maven-api-model/src/main/mdo/model.vm b/api/maven-api-model/src/main/mdo/model.vm
new file mode 100644
index 0000000000..9b3c2382ed
--- /dev/null
+++ b/api/maven-api-model/src/main/mdo/model.vm
@@ -0,0 +1,529 @@
+#*
+ 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.
+*#
+#parse ( "src/main/mdo/common.vm" )
+#
+#set ( $package = "${packageModelV4}" )
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#foreach ( $class in $model.allClasses )
+ #set ( $ancestors = $Helper.ancestors( $class ) )
+ #set ( $allFields = [] )
+ #set ( $inheritedFields = [] )
+ #foreach ( $cl in $ancestors )
+ #if ( $cl != $class )
+ #set ( $dummy = $inheritedFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $className = "${class.name}" )
+#MODELLO-VELOCITY#REDIRECT ${package.replace('.','/')}/${className}.java
+ #if ( $class.name != "InputLocation" && $class.name != "InputSource" )
+ #set ( $types = { } )
+ #set ( $imports = $class.getClass().forName("java.util.TreeSet").newInstance() )
+ #set ( $dummy = $imports.add( "java.io.Serializable" ) )
+ #set ( $dummy = $imports.add( "java.util.Collections" ) )
+ #set ( $dummy = $imports.add( "java.util.HashMap" ) )
+ #set ( $dummy = $imports.add( "java.util.Map" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Experimental" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Generated" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Immutable" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.NotThreadSafe" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.ThreadSafe" ) )
+ #foreach ( $field in $allFields )
+ #if ( $field.type == "java.util.List" )
+ #set ( $dummy = $imports.add( "java.util.ArrayList" ) )
+ #set ( $dummy = $imports.add( "java.util.Collection" ) )
+ #set ( $dummy = $imports.add( "java.util.List" ) )
+ #set ( $dummy = $types.put( $field, "List<" + $field.to + ">" ) )
+ #elseif ( $field.type == "DOM" )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.xml.Dom" ) )
+ #set ( $dummy = $types.put( $field, "Dom" ) )
+ #else
+ #set ( $fieldType = ${types.getOrDefault($field.type,$field.type)} )
+ #set ( $idx = $fieldType.lastIndexOf('.') )
+ #if ( $idx > 0 )
+ #set ( $dummy = $imports.add( $fieldType ) )
+ #set ( $dummy = $types.put( $fieldType, $fieldType.substring( $idx + 1 ) ) )
+ #end
+ #end
+ #end
+ #set ( $eq = "" )
+ #set ( $hc = "" )
+ #foreach ( $field in $allFields )
+ #if ( $field.identifier )
+ #set ( $dummy = $imports.add( "java.util.Objects" ) )
+ #set ( $dummy = $identifiers.add( $field ) )
+ #if ( $eq == "" )
+ #set ( $eq = "Objects.equals( this.${field.name}, that.${field.name} )" )
+ #else
+ #set ( $eq = "$eq && Objects.equals( this.${field.name}, that.${field.name} )" )
+ #end
+ #if ( $hc == "" )
+ #set ( $hc = "${field.name}" )
+ #else
+ #set ( $hc = "$hc, this.${field.name}" )
+ #end
+ #end
+ #end
+// =================== DO NOT EDIT THIS FILE ====================
+// Generated by Maven, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+ #foreach ( $imp in $imports )
+import $imp;
+ #end
+
+/**
+ #foreach ( $line in ${class.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+@Experimental
+@Generated @ThreadSafe @Immutable
+public class ${class.name}
+ #if ( $class.superClass )
+ extends ${class.superClass}
+ #end
+ #if ( $locationTracking )
+ implements Serializable, InputLocationTracker
+ #else
+ implements Serializable
+ #end
+{
+ #if ( $class == $root )
+ final String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ /**
+ #foreach ( $line in ${field.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ final ${type} $field.name;
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ /** Location of the xml element for this object. */
+ final InputLocation location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ /** Location of the xml element for the field ${field.name}. */
+ final InputLocation ${field.name}Location;
+ #end
+ #if ( ! $class.superClass )
+ /** Other locations */
+ final Map locations;
+ #end
+ #end
+
+ /**
+ * Constructor for this class, package protected.
+ * @see Builder#build()
+ */
+ ${class.name}(
+ #if ( $class == $root )
+ String modelEncoding,
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ $type $field.name${sep}
+ #end
+ #if ( $locationTracking )
+ Map locations,
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ InputLocation location${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ InputLocation ${field.name}Location${sep}
+ #end
+ #end
+ )
+ {
+ #if ( $class.superClass )
+ super(
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}${sep}
+ #end
+ #if ( $locationTracking )
+ locations,
+ #set ( $sep = "#if(${inheritedFields.size()}>0),#end" )
+ location${sep}
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}Location${sep}
+ #end
+ #end
+ );
+ #end
+ #if ( $class == $root )
+ this.modelEncoding = modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" || $field.type == "java.util.Map" )
+ this.${field.name} = ImmutableCollections.copy( ${field.name} );
+ #else
+ this.${field.name} = ${field.name};
+ #end
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ this.locations = ImmutableCollections.copy( locations );
+ this.location = location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name}Location = ${field.name}Location;
+ #end
+ #end
+ }
+
+ #if ( ! $eq.empty )
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || !( o instanceof ${class.name} ) )
+ {
+ return false;
+ }
+ ${class.name} that = ( ${class.name} ) o;
+ return ${eq};
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash( ${hc} );
+ }
+
+ #end
+ #if ( $class == $root )
+ public String getModelEncoding()
+ {
+ return modelEncoding;
+ }
+
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type == "boolean" || $type == "Boolean" )
+ #set ( $pfx = "is" )
+ #else
+ #set ( $pfx = "get" )
+ #end
+ /**
+ #set ( $desc = ${field.description.trim()} )
+ #foreach ( $line in ${desc.split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" )
+ @Nonnull
+ #end
+ public ${type} ${pfx}${cap}()
+ {
+ return this.${field.name};
+ }
+
+ #end
+ #if ( $locationTracking )
+ /**
+ * Gets the location of the specified field in the input source.
+ */
+ public InputLocation getLocation( Object key )
+ {
+ if ( key instanceof String )
+ {
+ switch ( ( String ) key )
+ {
+ #if ( ! $class.superClass )
+ case "":
+ return location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ case "${field.name}":
+ return ${field.name}Location;
+ #end
+ }
+ }
+ #if ( $class.superClass )
+ return super.getLocation( key );
+ #else
+ return locations != null ? locations.get( key ) : null;
+ #end
+ }
+
+ #end
+ /**
+ * Creates a new builder with this object as the basis.
+ */
+ @Nonnull
+ public Builder with()
+ {
+ return newBuilder( this );
+ }
+ #foreach ( $field in $allFields )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ /** Creates a new ${class.name} instance using the specified ${field.name}. */
+ @Nonnull
+ public ${class.name} with${cap}( $type $field.name )
+ {
+ return with().${field.name}( $field.name ).build();
+ }
+ #end
+
+ /**
+ * Creates a new ${class.name} instance.
+ * Equivalent to {@code newInstance( true )}.
+ * @see #newInstance(boolean)
+ */
+ @Nonnull
+ public static ${class.name} newInstance()
+ {
+ return newInstance( true );
+ }
+
+ /**
+ * Creates a new ${class.name} instance using default values or not.
+ * Equivalent to {@code newBuilder( withDefaults ).build()}.
+ */
+ @Nonnull
+ public static ${class.name} newInstance( boolean withDefaults )
+ {
+ return newBuilder( withDefaults ).build();
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance.
+ * Equivalent to {@code newBuilder( true )}.
+ * @see #newBuilder(boolean)
+ */
+ @Nonnull
+ public static Builder newBuilder()
+ {
+ return newBuilder( true );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using default values or not.
+ */
+ @Nonnull
+ public static Builder newBuilder( boolean withDefaults )
+ {
+ return new Builder( withDefaults );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ * Equivalent to {@code newBuilder( from, false )}.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from )
+ {
+ return newBuilder( from, false );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from, boolean forceCopy )
+ {
+ return new Builder( from, forceCopy );
+ }
+
+ /**
+ * Builder class used to create ${class.name} instances.
+ * @see #with()
+ * @see #newBuilder()
+ */
+ @NotThreadSafe
+ public static class Builder
+ #if ( $class.superClass )
+ extends ${class.superClass}.Builder
+ #end
+ {
+ ${class.name} base;
+ #if ( $class == $root )
+ String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ #if ( $type == 'boolean' )
+ Boolean ${field.name};
+ #elseif ( $type == 'int' )
+ Integer ${field.name};
+ #else
+ ${type} ${field.name};
+ #end
+ #end
+ #if ( ! $class.superClass && $locationTracking )
+ Map locations;
+ #end
+
+ Builder( boolean withDefaults )
+ {
+ #if ( $class.superClass )
+ super( withDefaults );
+ #end
+ if ( withDefaults )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.defaultValue )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $field.type == "String" )
+ this.${field.name} = "${field.defaultValue}";
+ #elseif ( $field.type != "java.util.List" && $field.type != "java.util.Properties" )
+ this.${field.name} = ${field.defaultValue};
+ #end
+ #end
+ #end
+ }
+ }
+
+ Builder( ${class.name} base, boolean forceCopy )
+ {
+ #if ( $class.superClass )
+ super( base, forceCopy );
+ #end
+ if ( forceCopy )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name} = base.${field.name};
+ #end
+ }
+ else
+ {
+ this.base = base;
+ }
+ }
+
+ #if ( $class == $root )
+ @Nonnull
+ public Builder modelEncoding( String modelEncoding )
+ {
+ this.modelEncoding = modelEncoding;
+ return this;
+ }
+
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ @Nonnull
+ public Builder ${field.name}( ${type} ${field.name} )
+ {
+ this.${field.name} = ${field.name};
+ return this;
+ }
+
+ #end
+
+ #if ( $locationTracking )
+ @Nonnull
+ public Builder location( Object key, InputLocation location )
+ {
+ if ( location != null )
+ {
+ if ( this.locations == null )
+ {
+ this.locations = new HashMap<>();
+ }
+ this.locations.put( key, location );
+ }
+ return this;
+ }
+
+ #end
+ @Nonnull
+ public ${class.name} build()
+ {
+ if ( base != null
+ #foreach ( $field in $allFields )
+ && ( ${field.name} == null || ${field.name} == base.${field.name} )
+ #end
+ )
+ {
+ return base;
+ }
+ #if ( $locationTracking )
+ Map locations = null;
+ InputLocation location = null;
+ #foreach ( $field in $allFields )
+ InputLocation ${field.name}Location = null;
+ #end
+ if ( this.locations != null )
+ {
+ locations = this.locations;
+ location = locations.remove( "" );
+ #foreach ( $field in $allFields )
+ ${field.name}Location = locations.remove( "${field.name}" );
+ #end
+ }
+ #end
+ return new ${class.name}(
+ #if ( $class == $root )
+ modelEncoding != null ? modelEncoding : ( base != null ? base.modelEncoding : "UTF-8" ),
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #if ( $field.type == "boolean" || $field.type == "int" )
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : ${field.defaultValue} )${sep}
+ #else
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : null )${sep}
+ #end
+ #end
+ #if ( $locationTracking )
+ locations != null ? locations : ( base != null ? base.locations : null ),
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ location != null ? location : ( base != null ? base.location : null )${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ ${field.name}Location != null ? ${field.name}Location : ( base != null ? base.${field.name}Location : null )${sep}
+ #end
+ #end
+ );
+ }
+ }
+
+ #foreach ( $cs in $class.getCodeSegments($version) )
+$cs.code
+ #end
+}
+ #end
+#end
diff --git a/api/maven-api-settings/pom.xml b/api/maven-api-settings/pom.xml
new file mode 100644
index 0000000000..e6b3c9c0eb
--- /dev/null
+++ b/api/maven-api-settings/pom.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven-api
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ maven-api-settings
+
+ Maven API Settings
+ Maven API Settings model.
+
+
+
+ org.apache.maven
+ maven-api-xml
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.2.0
+
+
+ attach-mdo
+
+ attach-artifact
+
+
+
+
+ src/main/mdo/settings.mdo
+ mdo
+
+
+
+
+
+
+
+ org.apache.maven
+ modello-plugin-velocity
+ 4.0.0-alpha-1-SNAPSHOT
+
+ 2.0.0
+
+ src/main/mdo/settings.mdo
+
+
+ src/main/mdo/model.vm
+
+
+ packageModelV4=org.apache.maven.api.settings
+
+
+
+
+ modello
+
+ velocity
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ **/package-info.java
+
+
+
+
+
+
+
diff --git a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/ImmutableCollections.java b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/ImmutableCollections.java
new file mode 100644
index 0000000000..850e0ef665
--- /dev/null
+++ b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/ImmutableCollections.java
@@ -0,0 +1,738 @@
+package org.apache.maven.api.settings;
+
+/*
+ * 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.AbstractList;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+class ImmutableCollections
+{
+
+ private static final List> EMPTY_LIST = new AbstractImmutableList()
+ {
+ @Override
+ public Object get( int index )
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+
+ private static final Map, ?> EMPTY_MAP = new AbstractImmutableMap()
+ {
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ @Override
+ public boolean hasNext()
+ {
+ return false;
+ }
+ @Override
+ public Entry next()
+ {
+ throw new NoSuchElementException();
+ }
+ };
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+ }
+ };
+
+ static List copy( Collection collection )
+ {
+ if ( collection == null )
+ {
+ return emptyList();
+ }
+ else if ( collection instanceof AbstractImmutableList )
+ {
+ return ( List ) collection;
+ }
+ else
+ {
+ switch ( collection.size() )
+ {
+ case 0:
+ return emptyList();
+ case 1:
+ return singletonList( collection.iterator().next() );
+ case 2:
+ Iterator it = collection.iterator();
+ return new List2<>( it.next(), it.next() );
+ default:
+ return new ListN<>( collection );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static List emptyList()
+ {
+ return ( List ) EMPTY_LIST;
+ }
+
+ static List singletonList( E element )
+ {
+ return new List1<>( element );
+ }
+
+ static Map copy( Map map )
+ {
+ if ( map == null )
+ {
+ return emptyMap();
+ }
+ else if ( map instanceof AbstractImmutableMap )
+ {
+ return map;
+ }
+ else
+ {
+ switch ( map.size() )
+ {
+ case 0:
+ return emptyMap();
+ case 1:
+ Map.Entry entry = map.entrySet().iterator().next();
+ return singletonMap( entry.getKey(), entry.getValue() );
+ default:
+ return new MapN<>( map );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static Map emptyMap()
+ {
+ return ( Map ) EMPTY_MAP;
+ }
+
+ static Map singletonMap( K key, V value )
+ {
+ return new Map1<>( key, value );
+ }
+
+ static Properties copy( Properties properties )
+ {
+ if ( properties instanceof ROProperties )
+ {
+ return properties;
+ }
+ return new ROProperties( properties );
+ }
+
+ private static class List1 extends AbstractImmutableList
+ {
+ private final E element;
+
+ private List1( E element )
+ {
+ this.element = element;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ }
+
+ private static class List2 extends AbstractImmutableList
+ {
+ private final E element1;
+ private final E element2;
+
+ private List2( E element1, E element2 )
+ {
+ this.element1 = element1;
+ this.element2 = element2;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element1;
+ }
+ else if ( index == 1 )
+ {
+ return element2;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 2;
+ }
+ }
+
+ private static class ListN extends AbstractImmutableList
+ {
+ private final Object[] elements;
+
+ private ListN( Collection elements )
+ {
+ this.elements = elements.toArray();
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public E get( int index )
+ {
+ return ( E ) elements[ index ];
+ }
+
+ @Override
+ public int size()
+ {
+ return elements.length;
+ }
+ }
+
+ private abstract static class AbstractImmutableList extends AbstractList implements RandomAccess
+ {
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean addAll( Collection extends E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( UnaryOperator operator )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void sort( Comparator super E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return new Itr( index );
+ }
+
+ @Override
+ public List subList( int fromIndex, int toIndex )
+ {
+ if ( fromIndex < 0 )
+ {
+ throw new IndexOutOfBoundsException( "fromIndex = " + fromIndex );
+ }
+ if ( toIndex > size() )
+ {
+ throw new IndexOutOfBoundsException( "toIndex = " + toIndex );
+ }
+ if ( fromIndex > toIndex )
+ {
+ throw new IllegalArgumentException( "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")" );
+ }
+ return new SubList( fromIndex, toIndex );
+ }
+
+ protected IndexOutOfBoundsException outOfBounds( int index )
+ {
+ return new IndexOutOfBoundsException( "Index: " + index + ", Size: " + size() );
+ }
+
+ private class SubList extends AbstractImmutableList
+ {
+ private final int fromIndex;
+ private final int toIndex;
+
+ private SubList( int fromIndex, int toIndex )
+ {
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return AbstractImmutableList.this.get( fromIndex + index );
+ }
+
+ @Override
+ public int size()
+ {
+ return toIndex - fromIndex;
+ }
+ }
+
+ private class Itr implements ListIterator
+ {
+ int index;
+
+ private Itr( int index )
+ {
+ this.index = index;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ @Override
+ public E next()
+ {
+ return get( index++ );
+ }
+
+ @Override
+ public boolean hasPrevious()
+ {
+ return index > 0;
+ }
+
+ @Override
+ public E previous()
+ {
+ return get( --index );
+ }
+
+ @Override
+ public int nextIndex()
+ {
+ return index;
+ }
+
+ @Override
+ public int previousIndex()
+ {
+ return index - 1;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void set( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void add( E e )
+ {
+ throw uoe();
+ }
+ }
+ }
+
+ private static class ROProperties extends Properties
+ {
+ private ROProperties( Properties props )
+ {
+ super();
+ if ( props != null )
+ {
+ // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
+ for ( Map.Entry e : props.entrySet() )
+ {
+ super.put( e.getKey(), e.getValue() );
+ }
+ }
+ }
+
+ @Override
+ public Object put( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object remove( Object key )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void putAll( Map, ?> t )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( BiFunction super Object, ? super Object, ?> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object putIfAbsent( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( Object key, Object oldValue, Object newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object replace( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfAbsent( Object key, Function super Object, ?> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfPresent( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object compute( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object merge( Object key, Object value, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private static class Map1 extends AbstractImmutableMap
+ {
+ private final Entry entry;
+
+ private Map1( K key, V value )
+ {
+ this.entry = new SimpleImmutableEntry<>( key, value );
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index == 0;
+ }
+
+ @Override
+ public Entry next()
+ {
+ if ( index++ == 0 )
+ {
+ return entry;
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ };
+ }
+ }
+
+ private static class MapN extends AbstractImmutableMap
+ {
+ private final Object[] entries;
+
+ private MapN( Map map )
+ {
+ entries = map != null ? map.entrySet().toArray() : new Object[0];
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index < entries.length;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public Entry next()
+ {
+ if ( index < entries.length )
+ {
+ return ( Entry ) entries[index++];
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return entries.length;
+ }
+ };
+ }
+ }
+
+ private abstract static class AbstractImmutableMap extends AbstractMap
+ {
+ @Override
+ public void replaceAll( BiFunction super K, ? super V, ? extends V> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V putIfAbsent( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( K key, V oldValue, V newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V replace( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfAbsent( K key, Function super K, ? extends V> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfPresent( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V compute( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V merge( K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private abstract static class AbstractImmutableSet extends AbstractSet
+ {
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+ }
+
+ private static UnsupportedOperationException uoe()
+ {
+ return new UnsupportedOperationException();
+ }
+
+}
diff --git a/api/maven-api-settings/src/main/mdo/common.vm b/api/maven-api-settings/src/main/mdo/common.vm
new file mode 100644
index 0000000000..aa3d17a039
--- /dev/null
+++ b/api/maven-api-settings/src/main/mdo/common.vm
@@ -0,0 +1,21 @@
+#*
+ 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.
+*#
+##
+## Nothing special to do here
+##
\ No newline at end of file
diff --git a/api/maven-api-settings/src/main/mdo/model.vm b/api/maven-api-settings/src/main/mdo/model.vm
new file mode 100644
index 0000000000..4eb6f45067
--- /dev/null
+++ b/api/maven-api-settings/src/main/mdo/model.vm
@@ -0,0 +1,521 @@
+#*
+ 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.
+*#
+#parse ( "src/main/mdo/common.vm" )
+#
+#set ( $package = "${packageModelV4}" )
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#foreach ( $class in $model.allClasses )
+ #set ( $ancestors = $Helper.ancestors( $class ) )
+ #set ( $allFields = [] )
+ #set ( $inheritedFields = [] )
+ #foreach ( $cl in $ancestors )
+ #if ( $cl != $class )
+ #set ( $dummy = $inheritedFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $className = "${class.name}" )
+#MODELLO-VELOCITY#REDIRECT ${package.replace('.','/')}/${className}.java
+ #if ( $class.name != "InputLocation" && $class.name != "InputSource" )
+ #set ( $types = { } )
+ #set ( $imports = $class.getClass().forName("java.util.TreeSet").newInstance() )
+ #set ( $dummy = $imports.add( "java.io.Serializable" ) )
+ #set ( $dummy = $imports.add( "java.util.Collections" ) )
+ #set ( $dummy = $imports.add( "java.util.HashMap" ) )
+ #set ( $dummy = $imports.add( "java.util.Map" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Experimental" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Generated" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Immutable" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.NotThreadSafe" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.ThreadSafe" ) )
+ #foreach ( $field in $allFields )
+ #if ( $field.type == "java.util.List" )
+ #set ( $dummy = $imports.add( "java.util.ArrayList" ) )
+ #set ( $dummy = $imports.add( "java.util.Collection" ) )
+ #set ( $dummy = $imports.add( "java.util.List" ) )
+ #set ( $dummy = $types.put( $field, "List<" + $field.to + ">" ) )
+ #elseif ( $field.type == "DOM" )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.xml.Dom" ) )
+ #set ( $dummy = $types.put( $field, "Dom" ) )
+ #else
+ #set ( $fieldType = ${types.getOrDefault($field.type,$field.type)} )
+ #set ( $idx = $fieldType.lastIndexOf('.') )
+ #if ( $idx > 0 )
+ #set ( $dummy = $imports.add( $fieldType ) )
+ #set ( $dummy = $types.put( $fieldType, $fieldType.substring( $idx + 1 ) ) )
+ #end
+ #end
+ #end
+ #set ( $eq = "" )
+ #set ( $hc = "" )
+ #foreach ( $field in $allFields )
+ #if ( $field.identifier )
+ #set ( $dummy = $imports.add( "java.util.Objects" ) )
+ #set ( $dummy = $identifiers.add( $field ) )
+ #if ( $eq == "" )
+ #set ( $eq = "Objects.equals( this.${field.name}, that.${field.name} )" )
+ #else
+ #set ( $eq = "$eq && Objects.equals( this.${field.name}, that.${field.name} )" )
+ #end
+ #if ( $hc == "" )
+ #set ( $hc = "${field.name}" )
+ #else
+ #set ( $hc = "$hc, this.${field.name}" )
+ #end
+ #end
+ #end
+// =================== DO NOT EDIT THIS FILE ====================
+// Generated by Maven, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+ #foreach ( $imp in $imports )
+import $imp;
+ #end
+
+/**
+ #foreach ( $line in ${class.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+@Experimental
+@Generated @ThreadSafe @Immutable
+public class ${class.name}
+ #if ( $class.superClass )
+ extends ${class.superClass}
+ #end
+ #if ( $locationTracking )
+ implements Serializable, InputLocationTracker
+ #else
+ implements Serializable
+ #end
+{
+ #if ( $class == $root )
+ final String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ /**
+ #foreach ( $line in ${field.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ final ${type} $field.name;
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ /** Location of the xml element for this object. */
+ final InputLocation location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ /** Location of the xml element for the field ${field.name}. */
+ final InputLocation ${field.name}Location;
+ #end
+ #if ( ! $class.superClass )
+ /** Other locations */
+ final Map locations;
+ #end
+ #end
+
+ /**
+ * Constructor for this class, package protected.
+ * @see Builder#build()
+ */
+ ${class.name}(
+ #if ( $class == $root )
+ String modelEncoding,
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ $type $field.name${sep}
+ #end
+ #if ( $locationTracking )
+ Map locations,
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ InputLocation location${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ InputLocation ${field.name}Location${sep}
+ #end
+ #end
+ )
+ {
+ #if ( $class.superClass )
+ super(
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}${sep}
+ #end
+ #if ( $locationTracking )
+ locations,
+ #set ( $sep = "#if(${inheritedFields.size()}>0),#end" )
+ location${sep}
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}Location${sep}
+ #end
+ #end
+ );
+ #end
+ #if ( $class == $root )
+ this.modelEncoding = modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" || $field.type == "java.util.Map" )
+ this.${field.name} = ImmutableCollections.copy( ${field.name} );
+ #else
+ this.${field.name} = ${field.name};
+ #end
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ this.locations = ImmutableCollections.copy( locations );
+ this.location = location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name}Location = ${field.name}Location;
+ #end
+ #end
+ }
+
+ #if ( ! $eq.empty )
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || !( o instanceof ${class.name} ) )
+ {
+ return false;
+ }
+ ${class.name} that = ( ${class.name} ) o;
+ return ${eq};
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash( ${hc} );
+ }
+
+ #end
+ #if ( $class == $root )
+ public String getModelEncoding()
+ {
+ return modelEncoding;
+ }
+
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type == "boolean" || $type == "Boolean" )
+ #set ( $pfx = "is" )
+ #else
+ #set ( $pfx = "get" )
+ #end
+ /**
+ #set ( $desc = ${field.description.trim()} )
+ #foreach ( $line in ${desc.split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" )
+ @Nonnull
+ #end
+ public ${type} ${pfx}${cap}()
+ {
+ return this.${field.name};
+ }
+
+ #end
+ #if ( $locationTracking )
+ /**
+ * Gets the location of the specified field in the input source.
+ */
+ public InputLocation getLocation( Object key )
+ {
+ if ( key instanceof String )
+ {
+ switch ( ( String ) key )
+ {
+ #if ( ! $class.superClass )
+ case "":
+ return location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ case "${field.name}":
+ return ${field.name}Location;
+ #end
+ }
+ }
+ #if ( $class.superClass )
+ return super.getLocation( key );
+ #else
+ return locations != null ? locations.get( key ) : null;
+ #end
+ }
+
+ #end
+ /**
+ * Creates a new builder with this object as the basis.
+ */
+ @Nonnull
+ public Builder with()
+ {
+ return newBuilder( this );
+ }
+ #foreach ( $field in $allFields )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ /** Creates a new ${class.name} instance using the specified ${field.name}. */
+ @Nonnull
+ public ${class.name} with${cap}( $type $field.name )
+ {
+ return with().${field.name}( $field.name ).build();
+ }
+ #end
+
+ /**
+ * Creates a new ${class.name} instance.
+ * Equivalent to {@code newInstance( true )}.
+ * @see #newInstance(boolean)
+ */
+ @Nonnull
+ public static ${class.name} newInstance()
+ {
+ return newInstance( true );
+ }
+
+ /**
+ * Creates a new ${class.name} instance using default values or not.
+ * Equivalent to {@code newBuilder( withDefaults ).build()}.
+ */
+ @Nonnull
+ public static ${class.name} newInstance( boolean withDefaults )
+ {
+ return newBuilder( withDefaults ).build();
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance.
+ * Equivalent to {@code newBuilder( true )}.
+ * @see #newBuilder(boolean)
+ */
+ @Nonnull
+ public static Builder newBuilder()
+ {
+ return newBuilder( true );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using default values or not.
+ */
+ @Nonnull
+ public static Builder newBuilder( boolean withDefaults )
+ {
+ return new Builder( withDefaults );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ * Equivalent to {@code newBuilder( from, false )}.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from )
+ {
+ return newBuilder( from, false );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from, boolean forceCopy )
+ {
+ return new Builder( from, forceCopy );
+ }
+
+ /**
+ * Builder class used to create ${class.name} instances.
+ * @see #with()
+ * @see #newBuilder()
+ */
+ @NotThreadSafe
+ public static class Builder
+ #if ( $class.superClass )
+ extends ${class.superClass}.Builder
+ #end
+ {
+ ${class.name} base;
+ #if ( $class == $root )
+ String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ #if ( $type == 'boolean' )
+ Boolean ${field.name};
+ #elseif ( $type == 'int' )
+ Integer ${field.name};
+ #else
+ ${type} ${field.name};
+ #end
+ #end
+ #if ( ! $class.superClass && $locationTracking )
+ Map locations;
+ #end
+
+ Builder( boolean withDefaults )
+ {
+ #if ( $class.superClass )
+ super( withDefaults );
+ #end
+ if ( withDefaults )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.defaultValue )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $field.type == "String" )
+ this.${field.name} = "${field.defaultValue}";
+ #elseif ( $field.type != "java.util.List" && $field.type != "java.util.Properties" )
+ this.${field.name} = ${field.defaultValue};
+ #end
+ #end
+ #end
+ }
+ }
+
+ Builder( ${class.name} base, boolean forceCopy )
+ {
+ #if ( $class.superClass )
+ super( base, forceCopy );
+ #end
+ if ( forceCopy )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name} = base.${field.name};
+ #end
+ }
+ else
+ {
+ this.base = base;
+ }
+ }
+
+ #if ( $class == $root )
+ @Nonnull
+ public Builder modelEncoding( String modelEncoding )
+ {
+ this.modelEncoding = modelEncoding;
+ return this;
+ }
+
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ @Nonnull
+ public Builder ${field.name}( ${type} ${field.name} )
+ {
+ this.${field.name} = ${field.name};
+ return this;
+ }
+
+ #end
+
+ #if ( $locationTracking )
+ @Nonnull
+ public Builder location( Object key, InputLocation location )
+ {
+ if ( location != null )
+ {
+ if ( this.locations == null )
+ {
+ this.locations = new HashMap<>();
+ }
+ this.locations.put( key, location );
+ }
+ return this;
+ }
+
+ #end
+ @Nonnull
+ public ${class.name} build()
+ {
+ if ( base != null
+ #foreach ( $field in $allFields )
+ && ( ${field.name} == null || ${field.name} == base.${field.name} )
+ #end
+ )
+ {
+ return base;
+ }
+ #if ( $locationTracking )
+ Map locations = new HashMap<>( this.locations != null ? this.locations : ( base != null ? base.locations : Collections.emptyMap() ) );
+ InputLocation location = locations.remove( "" );
+ #foreach ( $field in $allFields )
+ InputLocation ${field.name}Location = locations.remove( "${field.name}" );
+ #end
+ #end
+ return new ${class.name}(
+ #if ( $class == $root )
+ modelEncoding != null ? modelEncoding : ( base != null ? base.modelEncoding : "UTF-8" ),
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #if ( $field.type == "boolean" || $field.type == "int" )
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : ${field.defaultValue} )${sep}
+ #else
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : null )${sep}
+ #end
+ #end
+ #if ( $locationTracking )
+ locations,
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ location != null ? location : ( base != null ? base.location : null )${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ ${field.name}Location != null ? ${field.name}Location : ( base != null ? base.${field.name}Location : null )${sep}
+ #end
+ #end
+ );
+ }
+ }
+
+ #foreach ( $cs in $class.getCodeSegments($version) )
+$cs.code
+ #end
+}
+ #end
+#end
diff --git a/maven-settings/src/main/mdo/settings.mdo b/api/maven-api-settings/src/main/mdo/settings.mdo
similarity index 99%
rename from maven-settings/src/main/mdo/settings.mdo
rename to api/maven-api-settings/src/main/mdo/settings.mdo
index 4500560ca6..6a5757bb89 100644
--- a/maven-settings/src/main/mdo/settings.mdo
+++ b/api/maven-api-settings/src/main/mdo/settings.mdo
@@ -654,9 +654,9 @@
StringBuilder sb = new StringBuilder( 128 );
sb.append( "Mirror[" );
sb.append( "id=" ).append( this.getId() );
- sb.append( ",mirrorOf=" ).append( mirrorOf );
- sb.append( ",url=" ).append( this.url );
- sb.append( ",name=" ).append( this.name );
+ sb.append( ",mirrorOf=" ).append( this.getMirrorOf() );
+ sb.append( ",url=" ).append( this.getUrl() );
+ sb.append( ",name=" ).append( this.getName() );
if ( isBlocked() )
{
sb.append( ",blocked" );
@@ -874,14 +874,11 @@
public boolean equals( Object obj )
{
RepositoryBase other = (RepositoryBase) obj;
-
boolean retValue = false;
-
- if ( id != null )
+ if ( this.getId() != null )
{
- retValue = id.equals( other.id );
+ retValue = this.getId().equals( other.getId() );
}
-
return retValue;
}
]]>
diff --git a/api/maven-api-settings/src/site/apt/index.apt b/api/maven-api-settings/src/site/apt/index.apt
new file mode 100644
index 0000000000..2b42ccd16a
--- /dev/null
+++ b/api/maven-api-settings/src/site/apt/index.apt
@@ -0,0 +1,36 @@
+~~ 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.
+
+ -----
+ Introduction
+ -----
+ Vincent Siveton
+ -----
+ 2006-11-04
+ -----
+
+Maven Settings Model
+
+ This is strictly the model for Maven settings.
+
+ The following are generated from this model:
+
+ * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser
+
+ * A {{{./settings.html}Descriptor Reference}}
+
+ * An {{{https://maven.apache.org/xsd/settings-1.2.0.xsd}XSD}}
diff --git a/api/maven-api-settings/src/site/site.xml b/api/maven-api-settings/src/site/site.xml
new file mode 100644
index 0000000000..e475330c40
--- /dev/null
+++ b/api/maven-api-settings/src/site/site.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+ ${project.scm.url}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/maven-api-toolchain/pom.xml b/api/maven-api-toolchain/pom.xml
new file mode 100644
index 0000000000..cba137cf61
--- /dev/null
+++ b/api/maven-api-toolchain/pom.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ maven-api
+ org.apache.maven
+ 4.0.0-alpha-1-SNAPSHOT
+
+ 4.0.0
+
+ maven-api-toolchain
+
+ Maven API Toolchain
+ Maven API Toolchain model.
+
+
+
+ org.apache.maven
+ maven-api-xml
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.2.0
+
+
+ attach-mdo
+
+ attach-artifact
+
+
+
+
+ src/main/mdo/toolchains.mdo
+ mdo
+
+
+
+
+
+
+
+ org.apache.maven
+ modello-plugin-velocity
+ 4.0.0-alpha-1-SNAPSHOT
+
+ 1.1.0
+
+ src/main/mdo/toolchains.mdo
+
+
+ src/main/mdo/model.vm
+
+
+ packageModelV4=org.apache.maven.api.toolchain
+
+
+
+
+ modello
+
+ velocity
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ **/package-info.java
+
+
+
+
+
+
+
diff --git a/api/maven-api-toolchain/src/main/java/org/apache/maven/api/toolchain/ImmutableCollections.java b/api/maven-api-toolchain/src/main/java/org/apache/maven/api/toolchain/ImmutableCollections.java
new file mode 100644
index 0000000000..934a403316
--- /dev/null
+++ b/api/maven-api-toolchain/src/main/java/org/apache/maven/api/toolchain/ImmutableCollections.java
@@ -0,0 +1,738 @@
+package org.apache.maven.api.toolchain;
+
+/*
+ * 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.AbstractList;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+class ImmutableCollections
+{
+
+ private static final List> EMPTY_LIST = new AbstractImmutableList()
+ {
+ @Override
+ public Object get( int index )
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+
+ private static final Map, ?> EMPTY_MAP = new AbstractImmutableMap()
+ {
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ @Override
+ public boolean hasNext()
+ {
+ return false;
+ }
+ @Override
+ public Entry next()
+ {
+ throw new NoSuchElementException();
+ }
+ };
+ }
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+ };
+ }
+ };
+
+ static List copy( Collection collection )
+ {
+ if ( collection == null )
+ {
+ return emptyList();
+ }
+ else if ( collection instanceof AbstractImmutableList )
+ {
+ return ( List ) collection;
+ }
+ else
+ {
+ switch ( collection.size() )
+ {
+ case 0:
+ return emptyList();
+ case 1:
+ return singletonList( collection.iterator().next() );
+ case 2:
+ Iterator it = collection.iterator();
+ return new List2<>( it.next(), it.next() );
+ default:
+ return new ListN<>( collection );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static List emptyList()
+ {
+ return ( List ) EMPTY_LIST;
+ }
+
+ static List singletonList( E element )
+ {
+ return new List1<>( element );
+ }
+
+ static Map copy( Map map )
+ {
+ if ( map == null )
+ {
+ return emptyMap();
+ }
+ else if ( map instanceof AbstractImmutableMap )
+ {
+ return map;
+ }
+ else
+ {
+ switch ( map.size() )
+ {
+ case 0:
+ return emptyMap();
+ case 1:
+ Map.Entry entry = map.entrySet().iterator().next();
+ return singletonMap( entry.getKey(), entry.getValue() );
+ default:
+ return new MapN<>( map );
+ }
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ static Map emptyMap()
+ {
+ return ( Map ) EMPTY_MAP;
+ }
+
+ static Map singletonMap( K key, V value )
+ {
+ return new Map1<>( key, value );
+ }
+
+ static Properties copy( Properties properties )
+ {
+ if ( properties instanceof ROProperties )
+ {
+ return properties;
+ }
+ return new ROProperties( properties );
+ }
+
+ private static class List1 extends AbstractImmutableList
+ {
+ private final E element;
+
+ private List1( E element )
+ {
+ this.element = element;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ }
+
+ private static class List2 extends AbstractImmutableList
+ {
+ private final E element1;
+ private final E element2;
+
+ private List2( E element1, E element2 )
+ {
+ this.element1 = element1;
+ this.element2 = element2;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index == 0 )
+ {
+ return element1;
+ }
+ else if ( index == 1 )
+ {
+ return element2;
+ }
+ throw outOfBounds( index );
+ }
+
+ @Override
+ public int size()
+ {
+ return 2;
+ }
+ }
+
+ private static class ListN extends AbstractImmutableList
+ {
+ private final Object[] elements;
+
+ private ListN( Collection elements )
+ {
+ this.elements = elements.toArray();
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public E get( int index )
+ {
+ return ( E ) elements[ index ];
+ }
+
+ @Override
+ public int size()
+ {
+ return elements.length;
+ }
+ }
+
+ private abstract static class AbstractImmutableList extends AbstractList implements RandomAccess
+ {
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean addAll( Collection extends E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( UnaryOperator operator )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void sort( Comparator super E> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator()
+ {
+ return new Itr( 0 );
+ }
+
+ @Override
+ public ListIterator listIterator( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return new Itr( index );
+ }
+
+ @Override
+ public List subList( int fromIndex, int toIndex )
+ {
+ if ( fromIndex < 0 )
+ {
+ throw new IndexOutOfBoundsException( "fromIndex = " + fromIndex );
+ }
+ if ( toIndex > size() )
+ {
+ throw new IndexOutOfBoundsException( "toIndex = " + toIndex );
+ }
+ if ( fromIndex > toIndex )
+ {
+ throw new IllegalArgumentException( "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")" );
+ }
+ return new SubList( fromIndex, toIndex );
+ }
+
+ protected IndexOutOfBoundsException outOfBounds( int index )
+ {
+ return new IndexOutOfBoundsException( "Index: " + index + ", Size: " + size() );
+ }
+
+ private class SubList extends AbstractImmutableList
+ {
+ private final int fromIndex;
+ private final int toIndex;
+
+ private SubList( int fromIndex, int toIndex )
+ {
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ }
+
+ @Override
+ public E get( int index )
+ {
+ if ( index < 0 || index > size() )
+ {
+ throw outOfBounds( index );
+ }
+ return AbstractImmutableList.this.get( fromIndex + index );
+ }
+
+ @Override
+ public int size()
+ {
+ return toIndex - fromIndex;
+ }
+ }
+
+ private class Itr implements ListIterator
+ {
+ int index;
+
+ private Itr( int index )
+ {
+ this.index = index;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ @Override
+ public E next()
+ {
+ return get( index++ );
+ }
+
+ @Override
+ public boolean hasPrevious()
+ {
+ return index > 0;
+ }
+
+ @Override
+ public E previous()
+ {
+ return get( --index );
+ }
+
+ @Override
+ public int nextIndex()
+ {
+ return index;
+ }
+
+ @Override
+ public int previousIndex()
+ {
+ return index - 1;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void set( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void add( E e )
+ {
+ throw uoe();
+ }
+ }
+ }
+
+ private static class ROProperties extends Properties
+ {
+ private ROProperties( Properties props )
+ {
+ super();
+ if ( props != null )
+ {
+ // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
+ for ( Map.Entry e : props.entrySet() )
+ {
+ super.put( e.getKey(), e.getValue() );
+ }
+ }
+ }
+
+ @Override
+ public Object put( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object remove( Object key )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void putAll( Map, ?> t )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void replaceAll( BiFunction super Object, ? super Object, ?> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object putIfAbsent( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( Object key, Object oldValue, Object newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object replace( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfAbsent( Object key, Function super Object, ?> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object computeIfPresent( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object compute( Object key, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public Object merge( Object key, Object value, BiFunction super Object, ? super Object, ?> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private static class Map1 extends AbstractImmutableMap
+ {
+ private final Entry entry;
+
+ private Map1( K key, V value )
+ {
+ this.entry = new SimpleImmutableEntry<>( key, value );
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index == 0;
+ }
+
+ @Override
+ public Entry next()
+ {
+ if ( index++ == 0 )
+ {
+ return entry;
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return 1;
+ }
+ };
+ }
+ }
+
+ private static class MapN extends AbstractImmutableMap
+ {
+ private final Object[] entries;
+
+ private MapN( Map map )
+ {
+ entries = map != null ? map.entrySet().toArray() : new Object[0];
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return new AbstractImmutableSet>()
+ {
+ @Override
+ public Iterator> iterator()
+ {
+ return new Iterator>()
+ {
+ int index = 0;
+ @Override
+ public boolean hasNext()
+ {
+ return index < entries.length;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public Entry next()
+ {
+ if ( index < entries.length )
+ {
+ return ( Entry ) entries[index++];
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return entries.length;
+ }
+ };
+ }
+ }
+
+ private abstract static class AbstractImmutableMap extends AbstractMap
+ {
+ @Override
+ public void replaceAll( BiFunction super K, ? super V, ? extends V> function )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V putIfAbsent( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object key, Object value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean replace( K key, V oldValue, V newValue )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V replace( K key, V value )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfAbsent( K key, Function super K, ? extends V> mappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V computeIfPresent( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V compute( K key, BiFunction super K, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public V merge( K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction )
+ {
+ throw uoe();
+ }
+ }
+
+ private abstract static class AbstractImmutableSet extends AbstractSet
+ {
+ @Override
+ public boolean removeAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean add( E e )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean remove( Object o )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean retainAll( Collection> c )
+ {
+ throw uoe();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw uoe();
+ }
+
+ @Override
+ public boolean removeIf( Predicate super E> filter )
+ {
+ throw uoe();
+ }
+ }
+
+ private static UnsupportedOperationException uoe()
+ {
+ return new UnsupportedOperationException();
+ }
+
+}
diff --git a/api/maven-api-toolchain/src/main/mdo/common.vm b/api/maven-api-toolchain/src/main/mdo/common.vm
new file mode 100644
index 0000000000..aa3d17a039
--- /dev/null
+++ b/api/maven-api-toolchain/src/main/mdo/common.vm
@@ -0,0 +1,21 @@
+#*
+ 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.
+*#
+##
+## Nothing special to do here
+##
\ No newline at end of file
diff --git a/api/maven-api-toolchain/src/main/mdo/model.vm b/api/maven-api-toolchain/src/main/mdo/model.vm
new file mode 100644
index 0000000000..4eb6f45067
--- /dev/null
+++ b/api/maven-api-toolchain/src/main/mdo/model.vm
@@ -0,0 +1,521 @@
+#*
+ 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.
+*#
+#parse ( "src/main/mdo/common.vm" )
+#
+#set ( $package = "${packageModelV4}" )
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#foreach ( $class in $model.allClasses )
+ #set ( $ancestors = $Helper.ancestors( $class ) )
+ #set ( $allFields = [] )
+ #set ( $inheritedFields = [] )
+ #foreach ( $cl in $ancestors )
+ #if ( $cl != $class )
+ #set ( $dummy = $inheritedFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+ #end
+ #set ( $className = "${class.name}" )
+#MODELLO-VELOCITY#REDIRECT ${package.replace('.','/')}/${className}.java
+ #if ( $class.name != "InputLocation" && $class.name != "InputSource" )
+ #set ( $types = { } )
+ #set ( $imports = $class.getClass().forName("java.util.TreeSet").newInstance() )
+ #set ( $dummy = $imports.add( "java.io.Serializable" ) )
+ #set ( $dummy = $imports.add( "java.util.Collections" ) )
+ #set ( $dummy = $imports.add( "java.util.HashMap" ) )
+ #set ( $dummy = $imports.add( "java.util.Map" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Experimental" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Generated" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Immutable" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.NotThreadSafe" ) )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.ThreadSafe" ) )
+ #foreach ( $field in $allFields )
+ #if ( $field.type == "java.util.List" )
+ #set ( $dummy = $imports.add( "java.util.ArrayList" ) )
+ #set ( $dummy = $imports.add( "java.util.Collection" ) )
+ #set ( $dummy = $imports.add( "java.util.List" ) )
+ #set ( $dummy = $types.put( $field, "List<" + $field.to + ">" ) )
+ #elseif ( $field.type == "DOM" )
+ #set ( $dummy = $imports.add( "org.apache.maven.api.xml.Dom" ) )
+ #set ( $dummy = $types.put( $field, "Dom" ) )
+ #else
+ #set ( $fieldType = ${types.getOrDefault($field.type,$field.type)} )
+ #set ( $idx = $fieldType.lastIndexOf('.') )
+ #if ( $idx > 0 )
+ #set ( $dummy = $imports.add( $fieldType ) )
+ #set ( $dummy = $types.put( $fieldType, $fieldType.substring( $idx + 1 ) ) )
+ #end
+ #end
+ #end
+ #set ( $eq = "" )
+ #set ( $hc = "" )
+ #foreach ( $field in $allFields )
+ #if ( $field.identifier )
+ #set ( $dummy = $imports.add( "java.util.Objects" ) )
+ #set ( $dummy = $identifiers.add( $field ) )
+ #if ( $eq == "" )
+ #set ( $eq = "Objects.equals( this.${field.name}, that.${field.name} )" )
+ #else
+ #set ( $eq = "$eq && Objects.equals( this.${field.name}, that.${field.name} )" )
+ #end
+ #if ( $hc == "" )
+ #set ( $hc = "${field.name}" )
+ #else
+ #set ( $hc = "$hc, this.${field.name}" )
+ #end
+ #end
+ #end
+// =================== DO NOT EDIT THIS FILE ====================
+// Generated by Maven, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+ #foreach ( $imp in $imports )
+import $imp;
+ #end
+
+/**
+ #foreach ( $line in ${class.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+@Experimental
+@Generated @ThreadSafe @Immutable
+public class ${class.name}
+ #if ( $class.superClass )
+ extends ${class.superClass}
+ #end
+ #if ( $locationTracking )
+ implements Serializable, InputLocationTracker
+ #else
+ implements Serializable
+ #end
+{
+ #if ( $class == $root )
+ final String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ /**
+ #foreach ( $line in ${field.description.trim().split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ final ${type} $field.name;
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ /** Location of the xml element for this object. */
+ final InputLocation location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ /** Location of the xml element for the field ${field.name}. */
+ final InputLocation ${field.name}Location;
+ #end
+ #if ( ! $class.superClass )
+ /** Other locations */
+ final Map locations;
+ #end
+ #end
+
+ /**
+ * Constructor for this class, package protected.
+ * @see Builder#build()
+ */
+ ${class.name}(
+ #if ( $class == $root )
+ String modelEncoding,
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ $type $field.name${sep}
+ #end
+ #if ( $locationTracking )
+ Map locations,
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ InputLocation location${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ InputLocation ${field.name}Location${sep}
+ #end
+ #end
+ )
+ {
+ #if ( $class.superClass )
+ super(
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}${sep}
+ #end
+ #if ( $locationTracking )
+ locations,
+ #set ( $sep = "#if(${inheritedFields.size()}>0),#end" )
+ location${sep}
+ #foreach ( $field in $inheritedFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+ ${field.name}Location${sep}
+ #end
+ #end
+ );
+ #end
+ #if ( $class == $root )
+ this.modelEncoding = modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" || $field.type == "java.util.Map" )
+ this.${field.name} = ImmutableCollections.copy( ${field.name} );
+ #else
+ this.${field.name} = ${field.name};
+ #end
+ #end
+ #if ( $locationTracking )
+ #if ( ! $class.superClass )
+ this.locations = ImmutableCollections.copy( locations );
+ this.location = location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name}Location = ${field.name}Location;
+ #end
+ #end
+ }
+
+ #if ( ! $eq.empty )
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || !( o instanceof ${class.name} ) )
+ {
+ return false;
+ }
+ ${class.name} that = ( ${class.name} ) o;
+ return ${eq};
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash( ${hc} );
+ }
+
+ #end
+ #if ( $class == $root )
+ public String getModelEncoding()
+ {
+ return modelEncoding;
+ }
+
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type == "boolean" || $type == "Boolean" )
+ #set ( $pfx = "is" )
+ #else
+ #set ( $pfx = "get" )
+ #end
+ /**
+ #set ( $desc = ${field.description.trim()} )
+ #foreach ( $line in ${desc.split("\n")} )
+ * ${line.trim()}
+ #end
+ */
+ #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" )
+ @Nonnull
+ #end
+ public ${type} ${pfx}${cap}()
+ {
+ return this.${field.name};
+ }
+
+ #end
+ #if ( $locationTracking )
+ /**
+ * Gets the location of the specified field in the input source.
+ */
+ public InputLocation getLocation( Object key )
+ {
+ if ( key instanceof String )
+ {
+ switch ( ( String ) key )
+ {
+ #if ( ! $class.superClass )
+ case "":
+ return location;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ case "${field.name}":
+ return ${field.name}Location;
+ #end
+ }
+ }
+ #if ( $class.superClass )
+ return super.getLocation( key );
+ #else
+ return locations != null ? locations.get( key ) : null;
+ #end
+ }
+
+ #end
+ /**
+ * Creates a new builder with this object as the basis.
+ */
+ @Nonnull
+ public Builder with()
+ {
+ return newBuilder( this );
+ }
+ #foreach ( $field in $allFields )
+ #set ( $cap = $Helper.capitalise( $field.name ) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ /** Creates a new ${class.name} instance using the specified ${field.name}. */
+ @Nonnull
+ public ${class.name} with${cap}( $type $field.name )
+ {
+ return with().${field.name}( $field.name ).build();
+ }
+ #end
+
+ /**
+ * Creates a new ${class.name} instance.
+ * Equivalent to {@code newInstance( true )}.
+ * @see #newInstance(boolean)
+ */
+ @Nonnull
+ public static ${class.name} newInstance()
+ {
+ return newInstance( true );
+ }
+
+ /**
+ * Creates a new ${class.name} instance using default values or not.
+ * Equivalent to {@code newBuilder( withDefaults ).build()}.
+ */
+ @Nonnull
+ public static ${class.name} newInstance( boolean withDefaults )
+ {
+ return newBuilder( withDefaults ).build();
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance.
+ * Equivalent to {@code newBuilder( true )}.
+ * @see #newBuilder(boolean)
+ */
+ @Nonnull
+ public static Builder newBuilder()
+ {
+ return newBuilder( true );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using default values or not.
+ */
+ @Nonnull
+ public static Builder newBuilder( boolean withDefaults )
+ {
+ return new Builder( withDefaults );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ * Equivalent to {@code newBuilder( from, false )}.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from )
+ {
+ return newBuilder( from, false );
+ }
+
+ /**
+ * Creates a new ${class.name} builder instance using the specified object as a basis.
+ */
+ @Nonnull
+ public static Builder newBuilder( ${class.name} from, boolean forceCopy )
+ {
+ return new Builder( from, forceCopy );
+ }
+
+ /**
+ * Builder class used to create ${class.name} instances.
+ * @see #with()
+ * @see #newBuilder()
+ */
+ @NotThreadSafe
+ public static class Builder
+ #if ( $class.superClass )
+ extends ${class.superClass}.Builder
+ #end
+ {
+ ${class.name} base;
+ #if ( $class == $root )
+ String modelEncoding;
+ #end
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ #if ( $type == 'boolean' )
+ Boolean ${field.name};
+ #elseif ( $type == 'int' )
+ Integer ${field.name};
+ #else
+ ${type} ${field.name};
+ #end
+ #end
+ #if ( ! $class.superClass && $locationTracking )
+ Map locations;
+ #end
+
+ Builder( boolean withDefaults )
+ {
+ #if ( $class.superClass )
+ super( withDefaults );
+ #end
+ if ( withDefaults )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ #if ( $field.defaultValue )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $field.type == "String" )
+ this.${field.name} = "${field.defaultValue}";
+ #elseif ( $field.type != "java.util.List" && $field.type != "java.util.Properties" )
+ this.${field.name} = ${field.defaultValue};
+ #end
+ #end
+ #end
+ }
+ }
+
+ Builder( ${class.name} base, boolean forceCopy )
+ {
+ #if ( $class.superClass )
+ super( base, forceCopy );
+ #end
+ if ( forceCopy )
+ {
+ #foreach ( $field in $class.getFields($version) )
+ this.${field.name} = base.${field.name};
+ #end
+ }
+ else
+ {
+ this.base = base;
+ }
+ }
+
+ #if ( $class == $root )
+ @Nonnull
+ public Builder modelEncoding( String modelEncoding )
+ {
+ this.modelEncoding = modelEncoding;
+ return this;
+ }
+
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+ #if ( $type.startsWith("List<") )
+ #set ( $type = ${type.replace('List<','Collection<')} )
+ #end
+ @Nonnull
+ public Builder ${field.name}( ${type} ${field.name} )
+ {
+ this.${field.name} = ${field.name};
+ return this;
+ }
+
+ #end
+
+ #if ( $locationTracking )
+ @Nonnull
+ public Builder location( Object key, InputLocation location )
+ {
+ if ( location != null )
+ {
+ if ( this.locations == null )
+ {
+ this.locations = new HashMap<>();
+ }
+ this.locations.put( key, location );
+ }
+ return this;
+ }
+
+ #end
+ @Nonnull
+ public ${class.name} build()
+ {
+ if ( base != null
+ #foreach ( $field in $allFields )
+ && ( ${field.name} == null || ${field.name} == base.${field.name} )
+ #end
+ )
+ {
+ return base;
+ }
+ #if ( $locationTracking )
+ Map locations = new HashMap<>( this.locations != null ? this.locations : ( base != null ? base.locations : Collections.emptyMap() ) );
+ InputLocation location = locations.remove( "" );
+ #foreach ( $field in $allFields )
+ InputLocation ${field.name}Location = locations.remove( "${field.name}" );
+ #end
+ #end
+ return new ${class.name}(
+ #if ( $class == $root )
+ modelEncoding != null ? modelEncoding : ( base != null ? base.modelEncoding : "UTF-8" ),
+ #end
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ #if ( $field.type == "boolean" || $field.type == "int" )
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : ${field.defaultValue} )${sep}
+ #else
+ ${field.name} != null ? ${field.name} : ( base != null ? base.${field.name} : null )${sep}
+ #end
+ #end
+ #if ( $locationTracking )
+ locations,
+ #set ( $sep = "#if(${allFields.size()}>0),#end" )
+ location != null ? location : ( base != null ? base.location : null )${sep}
+ #foreach ( $field in $allFields )
+ #set ( $sep = "#if(${locationTracking}&&$field!=${allFields[${allFields.size()} - 1]}),#end" )
+ ${field.name}Location != null ? ${field.name}Location : ( base != null ? base.${field.name}Location : null )${sep}
+ #end
+ #end
+ );
+ }
+ }
+
+ #foreach ( $cs in $class.getCodeSegments($version) )
+$cs.code
+ #end
+}
+ #end
+#end
diff --git a/maven-toolchain-model/src/main/mdo/toolchains.mdo b/api/maven-api-toolchain/src/main/mdo/toolchains.mdo
similarity index 98%
rename from maven-toolchain-model/src/main/mdo/toolchains.mdo
rename to api/maven-api-toolchain/src/main/mdo/toolchains.mdo
index 29f742ccaa..7090b94686 100644
--- a/maven-toolchain-model/src/main/mdo/toolchains.mdo
+++ b/api/maven-api-toolchain/src/main/mdo/toolchains.mdo
@@ -189,8 +189,8 @@
{
int result = 17;
- result = 37 * result + ( type != null ? type.hashCode() : 0 );
- result = 37 * result + ( provides != null ? provides.hashCode() : 0 );
+ result = 37 * result + ( getType() != null ? getType().hashCode() : 0 );
+ result = 37 * result + ( getProvides() != null ? getProvides().hashCode() : 0 );
return result;
} //-- int hashCode()
diff --git a/api/maven-api-xml/pom.xml b/api/maven-api-xml/pom.xml
new file mode 100644
index 0000000000..42ad25007a
--- /dev/null
+++ b/api/maven-api-xml/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven-api
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ maven-api-xml
+ Maven API XML
+
+
+
+ org.apache.maven
+ maven-api-meta
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+
+
diff --git a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java
new file mode 100644
index 0000000000..2b8d63eae0
--- /dev/null
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java
@@ -0,0 +1,129 @@
+package org.apache.maven.api.xml;
+
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+/**
+ * An immutable xml node.
+ *
+ * @since 4.0
+ */
+@Experimental
+@ThreadSafe @Immutable
+public interface Dom
+{
+
+ String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+
+ String CHILDREN_COMBINATION_MERGE = "merge";
+
+ String CHILDREN_COMBINATION_APPEND = "append";
+
+ /**
+ * This default mode for combining children DOMs during merge means that where element names match, the process will
+ * try to merge the element data, rather than putting the dominant and recessive elements (which share the same
+ * element name) as siblings in the resulting DOM.
+ */
+ String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+
+ String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+
+ String SELF_COMBINATION_OVERRIDE = "override";
+
+ String SELF_COMBINATION_MERGE = "merge";
+
+ String SELF_COMBINATION_REMOVE = "remove";
+
+ /**
+ * This default mode for combining a DOM node during merge means that where element names match, the process will
+ * try to merge the element attributes and values, rather than overriding the recessive element completely with the
+ * dominant one. This means that wherever the dominant element doesn't provide the value or a particular attribute,
+ * that value or attribute will be set from the recessive DOM node.
+ */
+ String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+
+ @Nonnull
+ String getName();
+
+ @Nullable
+ String getValue();
+
+ @Nonnull
+ Map getAttributes();
+
+ @Nullable
+ String getAttribute( @Nonnull String name );
+
+ @Nonnull
+ List getChildren();
+
+ @Nullable
+ Dom getChild( String name );
+
+ @Nullable
+ Object getInputLocation();
+
+ default Dom merge( @Nullable Dom source )
+ {
+ return merge( source, (Boolean) null );
+ }
+
+ Dom merge( @Nullable Dom source, @Nullable Boolean childMergeOverride );
+
+ Dom clone();
+
+ /**
+ * Merge recessive into dominant and return either {@code dominant}
+ * with merged information or a clone of {@code recessive} if
+ * {@code dominant} is {@code null}.
+ *
+ * @param dominant the node
+ * @param recessive if {@code null}, nothing will happen
+ * @return the merged node
+ */
+ @Nullable
+ static Dom merge( @Nullable Dom dominant, @Nullable Dom recessive )
+ {
+ return merge( dominant, recessive, null );
+ }
+
+ @Nullable
+ static Dom merge( @Nullable Dom dominant, @Nullable Dom recessive, @Nullable Boolean childMergeOverride )
+ {
+ if ( recessive == null )
+ {
+ return dominant;
+ }
+ if ( dominant == null )
+ {
+ return recessive;
+ }
+ return dominant.merge( recessive, childMergeOverride );
+ }
+
+}
diff --git a/api/modello-plugin-velocity/pom.xml b/api/modello-plugin-velocity/pom.xml
new file mode 100644
index 0000000000..2875135e73
--- /dev/null
+++ b/api/modello-plugin-velocity/pom.xml
@@ -0,0 +1,98 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven-api
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ modello-plugin-velocity
+ maven-plugin
+ Modello Velocity Plugin
+
+ Modello Velocity Plugin generates custom templates.
+
+
+
+ 3.6.4
+ 3.8.5
+
+
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ ${mavenPluginTools}
+ provided
+
+
+ org.apache.maven
+ maven-plugin-api
+ ${maven}
+ provided
+
+
+ *
+ *
+
+
+
+
+ org.apache.maven
+ maven-core
+ ${maven}
+ provided
+
+
+ *
+ *
+
+
+
+
+ org.codehaus.modello
+ modello-maven-plugin
+ 2.0.0
+
+
+ org.apache.velocity
+ velocity-engine-core
+ 2.3
+
+
+ org.codehaus.modello
+ modello-core
+ 2.0.0
+
+
+ org.codehaus.modello
+ modello-plugin-xml
+ 2.0.0
+
+
+ org.codehaus.plexus
+ plexus-utils
+
+
+
+
diff --git a/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/Helper.java b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/Helper.java
new file mode 100644
index 0000000000..0e9f285fdd
--- /dev/null
+++ b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/Helper.java
@@ -0,0 +1,154 @@
+package org.codehaus.modello.plugin.velocity;
+
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.modello.ModelloRuntimeException;
+import org.codehaus.modello.model.ModelAssociation;
+import org.codehaus.modello.model.ModelClass;
+import org.codehaus.modello.model.ModelField;
+import org.codehaus.modello.model.Version;
+import org.codehaus.modello.plugin.AbstractModelloGenerator;
+import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
+import org.codehaus.modello.plugins.xml.metadata.XmlClassMetadata;
+import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
+import org.codehaus.plexus.util.StringUtils;
+
+@SuppressWarnings( "unused" )
+public class Helper
+{
+ private final Version version;
+
+ public Helper( Version version )
+ {
+ this.version = version;
+ }
+
+ public String capitalise( String str )
+ {
+ return StringUtils.isEmpty( str ) ? str : Character.toTitleCase( str.charAt( 0 ) ) + str.substring( 1 );
+ }
+
+ public String uncapitalise( String str )
+ {
+ return StringUtils.isEmpty( str ) ? str : Character.toLowerCase( str.charAt( 0 ) ) + str.substring( 1 );
+ }
+
+ public String singular( String str )
+ {
+ return AbstractModelloGenerator.singular( str );
+ }
+
+ public List ancestors( ModelClass clazz )
+ {
+ List ancestors = new ArrayList<>();
+ for ( ModelClass cl = clazz; cl != null; cl = cl.getSuperClass() != null
+ ? cl.getModel().getClass( cl.getSuperClass(), version ) : null )
+ {
+ ancestors.add( 0, cl );
+ }
+ return ancestors;
+ }
+
+ public XmlClassMetadata xmlClassMetadata( ModelClass clazz )
+ {
+ return (XmlClassMetadata) clazz.getMetadata( XmlClassMetadata.ID );
+ }
+
+ public XmlFieldMetadata xmlFieldMetadata( ModelField field )
+ {
+ return (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+ }
+
+ public XmlAssociationMetadata xmAssociationMetadata( ModelField field )
+ {
+ return (XmlAssociationMetadata) ( (ModelAssociation) field )
+ .getAssociationMetadata( XmlAssociationMetadata.ID );
+ }
+
+ public boolean isFlatItems( ModelField field )
+ {
+ return field instanceof ModelAssociation && xmAssociationMetadata( field ).isFlatItems();
+ }
+
+ public List xmlFields( ModelClass modelClass )
+ {
+ List classes = new ArrayList<>();
+ // get the full inheritance
+ while ( modelClass != null )
+ {
+ classes.add( modelClass );
+ String superClass = modelClass.getSuperClass();
+ if ( superClass != null )
+ {
+ // superClass can be located outside (not generated by modello)
+ modelClass = modelClass.getModel().getClass( superClass, version, true );
+ }
+ else
+ {
+ modelClass = null;
+ }
+ }
+ List fields = new ArrayList<>();
+ for ( int i = classes.size() - 1; i >= 0; i-- )
+ {
+ modelClass = classes.get( i );
+ Iterator parentIter = fields.iterator();
+ fields = new ArrayList<>();
+ for ( ModelField field : modelClass.getFields( version ) )
+ {
+ XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+ if ( xmlFieldMetadata.isTransient() )
+ {
+ // just ignore xml.transient fields
+ continue;
+ }
+ if ( xmlFieldMetadata.getInsertParentFieldsUpTo() != null )
+ {
+ // insert fields from parent up to the specified field
+ boolean found = false;
+ while ( !found && parentIter.hasNext() )
+ {
+ ModelField parentField = parentIter.next();
+ fields.add( parentField );
+ found = parentField.getName().equals( xmlFieldMetadata.getInsertParentFieldsUpTo() );
+ }
+ if ( !found )
+ {
+ // interParentFieldsUpTo not found
+ throw new ModelloRuntimeException( "parent field not found: class "
+ + modelClass.getName() + " xml.insertParentFieldUpTo='"
+ + xmlFieldMetadata.getInsertParentFieldsUpTo() + "'" );
+ }
+ }
+ fields.add( field );
+ }
+ // add every remaining fields from parent class
+ while ( parentIter.hasNext() )
+ {
+ fields.add( parentIter.next() );
+ }
+ }
+ return fields;
+ }
+}
diff --git a/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/ModelloVelocityMojo.java b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/ModelloVelocityMojo.java
new file mode 100644
index 0000000000..604d54f542
--- /dev/null
+++ b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/ModelloVelocityMojo.java
@@ -0,0 +1,86 @@
+package org.codehaus.modello.plugin.velocity;
+
+/*
+ * 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 java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.modello.maven.AbstractModelloGeneratorMojo;
+
+/**
+ * Creates an XML schema from the model.
+ *
+ * @author Brett Porter
+ */
+@Mojo( name = "velocity", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true )
+public class ModelloVelocityMojo
+ extends AbstractModelloGeneratorMojo
+{
+ /**
+ * The output directory of the generated XML Schema.
+ */
+ @Parameter( defaultValue = "${project.build.directory}/generated-sources/modello", required = true )
+ private File outputDirectory;
+
+ @Parameter
+ private List templates;
+
+ @Parameter
+ private List params;
+
+ protected String getGeneratorType()
+ {
+ return "velocity";
+ }
+
+ protected void customizeParameters( Properties parameters )
+ {
+ super.customizeParameters( parameters );
+ Map params = this.params != null ? this.params.stream().collect( Collectors.toMap(
+ s -> s.substring( 0, s.indexOf( '=' ) ), s -> s.substring( s.indexOf( '=' ) + 1 )
+ ) ) : Collections.emptyMap();
+ parameters.put( "basedir", Objects.requireNonNull( getBasedir(), "basedir is null" ) );
+ parameters.put( VelocityGenerator.VELOCITY_TEMPLATES, String.join( ",", templates ) );
+ parameters.put( VelocityGenerator.VELOCITY_PARAMETERS, params );
+ }
+
+ protected boolean producesCompilableResult()
+ {
+ return true;
+ }
+
+ public File getOutputDirectory()
+ {
+ return outputDirectory;
+ }
+
+ public void setOutputDirectory( File outputDirectory )
+ {
+ this.outputDirectory = outputDirectory;
+ }
+}
diff --git a/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/VelocityGenerator.java b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/VelocityGenerator.java
new file mode 100644
index 0000000000..6f82631695
--- /dev/null
+++ b/api/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/VelocityGenerator.java
@@ -0,0 +1,166 @@
+package org.codehaus.modello.plugin.velocity;
+
+/*
+ * 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.IOException;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.runtime.RuntimeInstance;
+import org.codehaus.modello.ModelloException;
+import org.codehaus.modello.ModelloParameterConstants;
+import org.codehaus.modello.model.Model;
+import org.codehaus.modello.model.Version;
+import org.codehaus.modello.plugin.AbstractModelloGenerator;
+import org.codehaus.plexus.util.io.CachingWriter;
+
+public class VelocityGenerator
+ extends AbstractModelloGenerator
+{
+ public static final String VELOCITY_TEMPLATES = "modello.velocity.template";
+
+ public static final String VELOCITY_PARAMETERS = "modello.velocity.parameters";
+
+ @Override
+ public void generate( Model model, Properties parameters ) throws ModelloException
+ {
+ try
+ {
+ Map params = ( Map ) Objects.requireNonNull( parameters.get( VELOCITY_PARAMETERS ) );
+ String templates = getParameter( parameters, VELOCITY_TEMPLATES );
+ String output = getParameter( parameters, ModelloParameterConstants.OUTPUT_DIRECTORY );
+
+ Properties props = new Properties();
+ props.put( "resource.loader.file.path", getParameter( parameters, "basedir" ) );
+ RuntimeInstance velocity = new RuntimeInstance();
+ velocity.init( props );
+
+ VelocityContext context = new VelocityContext();
+ for ( Map.Entry prop : parameters.entrySet() )
+ {
+ context.put( prop.getKey().toString(), prop.getValue() );
+ }
+ for ( Map.Entry prop : params.entrySet() )
+ {
+ context.put( prop.getKey(), prop.getValue() );
+ }
+ Version version = new Version( getParameter( parameters, ModelloParameterConstants.VERSION ) );
+ context.put( "version", version );
+ context.put( "model", model );
+ context.put( "Helper", new Helper( version ) );
+
+ for ( String templatePath : templates.split( "," ) )
+ {
+ Template template = velocity.getTemplate( templatePath );
+
+ try ( Writer w = new RedirectingWriter( Paths.get( output ) ) )
+ {
+ template.merge( context, w );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ throw new ModelloException( "Unable to run velocity template", e );
+ }
+
+ }
+
+ static class RedirectingWriter extends Writer
+ {
+ Path dir;
+ StringBuilder sb = new StringBuilder();
+ Writer current;
+
+ RedirectingWriter( Path dir )
+ {
+ this.dir = dir;
+ }
+
+ @Override
+ public void write( char[] cbuf, int off, int len ) throws IOException
+ {
+ for ( int i = 0; i < len; i++ )
+ {
+ if ( cbuf[ off + i ] == '\n' )
+ {
+ if ( sb.length() > 0 && sb.charAt( sb.length() - 1 ) == '\r' )
+ {
+ sb.setLength( sb.length() - 1 );
+ }
+ writeLine( sb.toString() );
+ sb.setLength( 0 );
+ }
+ else
+ {
+ sb.append( cbuf[ off + i ] );
+ }
+ }
+ }
+
+ protected void writeLine( String line ) throws IOException
+ {
+ if ( line.startsWith( "#MODELLO-VELOCITY#REDIRECT " ) )
+ {
+ String file = line.substring( "#MODELLO-VELOCITY#REDIRECT ".length() );
+ if ( current != null )
+ {
+ current.close();
+ }
+ Path out = dir.resolve( file );
+ Files.createDirectories( out.getParent() );
+ current = new CachingWriter( out, StandardCharsets.UTF_8 );
+ }
+ else if ( current != null )
+ {
+ current.write( line );
+ current.write( "\n" );
+ }
+ }
+
+ @Override
+ public void flush() throws IOException
+ {
+ if ( current != null )
+ {
+ current.flush();
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ if ( current != null )
+ {
+ current.close();
+ current = null;
+ }
+ }
+ }
+
+}
diff --git a/api/modello-plugin-velocity/src/main/resources/META-INF/plexus/components.xml b/api/modello-plugin-velocity/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000000..ed745b2fc4
--- /dev/null
+++ b/api/modello-plugin-velocity/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+ org.codehaus.modello.plugin.ModelloGenerator
+ velocity
+ org.codehaus.modello.plugin.velocity.VelocityGenerator
+ per-lookup
+
+
+
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000000..ce098702c3
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven
+ 4.0.0-alpha-1-SNAPSHOT
+
+
+ maven-api
+ Maven API
+ pom
+
+
+ modello-plugin-velocity
+ maven-api-meta
+ maven-api-xml
+ maven-api-model
+ maven-api-settings
+ maven-api-toolchain
+ maven-api-core
+
+
+
diff --git a/build/checkstyle-suppressions.xml b/build/checkstyle-suppressions.xml
index 78e9e3c05e..45702996fb 100644
--- a/build/checkstyle-suppressions.xml
+++ b/build/checkstyle-suppressions.xml
@@ -26,5 +26,4 @@ under the License.
-
diff --git a/maven-bom/pom.xml b/maven-bom/pom.xml
index 4f9b6e370d..257eac644a 100644
--- a/maven-bom/pom.xml
+++ b/maven-bom/pom.xml
@@ -94,6 +94,11 @@ under the License.
maven-model
${project.version}
+
+ org.apache.maven
+ maven-api-core
+ ${project.version}
+
org.apache.maven
maven-model-builder
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
index 5f7957e706..2bfefbec4c 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
@@ -85,9 +85,9 @@ public class DefaultWagonManager
{
if ( id.equalsIgnoreCase( server.getId() ) )
{
- SettingsDecryptionResult result =
- settingsDecrypter.decrypt( new DefaultSettingsDecryptionRequest( server ) );
- server = result.getServer();
+ SettingsDecryptionResult result = settingsDecrypter.decrypt(
+ new DefaultSettingsDecryptionRequest( server.getDelegate() ) );
+ server = new Server( result.getServer() );
AuthenticationInfo authInfo = new AuthenticationInfo();
authInfo.setUserName( server.getUsername() );
@@ -124,9 +124,9 @@ public class DefaultWagonManager
{
if ( proxy.isActive() && protocol.equalsIgnoreCase( proxy.getProtocol() ) )
{
- SettingsDecryptionResult result =
- settingsDecrypter.decrypt( new DefaultSettingsDecryptionRequest( proxy ) );
- proxy = result.getProxy();
+ SettingsDecryptionResult result = settingsDecrypter.decrypt(
+ new DefaultSettingsDecryptionRequest( proxy.getDelegate() ) );
+ proxy = new Proxy( result.getProxy() );
ProxyInfo proxyInfo = new ProxyInfo();
proxyInfo.setHost( proxy.getHost() );
diff --git a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
index 6b378b7af1..2c94f7a6f6 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
@@ -19,19 +19,10 @@ package org.apache.maven.project;
* under the License.
*/
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.Repository;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
/** @deprecated */
@Deprecated
@@ -54,309 +45,24 @@ public final class ModelUtils
public static void mergePluginLists( PluginContainer childContainer, PluginContainer parentContainer,
boolean handleAsInheritance )
{
- if ( ( childContainer == null ) || ( parentContainer == null ) )
- {
- // nothing to do.
- return;
- }
-
- List parentPlugins = parentContainer.getPlugins();
-
- if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
- {
- parentPlugins = new ArrayList<>( parentPlugins );
-
- // If we're processing this merge as an inheritance, we have to build up a list of
- // plugins that were considered for inheritance.
- if ( handleAsInheritance )
- {
- for ( Iterator it = parentPlugins.iterator(); it.hasNext(); )
- {
- Plugin plugin = it.next();
-
- String inherited = plugin.getInherited();
-
- if ( ( inherited != null ) && !Boolean.parseBoolean( inherited ) )
- {
- it.remove();
- }
- }
- }
-
- List assembledPlugins = new ArrayList<>();
-
- Map childPlugins = childContainer.getPluginsAsMap();
-
- for ( Plugin parentPlugin : parentPlugins )
- {
- String parentInherited = parentPlugin.getInherited();
-
- // only merge plugin definition from the parent if at least one
- // of these is true:
- // 1. we're not processing the plugins in an inheritance-based merge
- // 2. the parent's flag is not set
- // 3. the parent's flag is set to true
- if ( !handleAsInheritance || ( parentInherited == null )
- || Boolean.parseBoolean( parentInherited ) )
- {
- Plugin childPlugin = childPlugins.get( parentPlugin.getKey() );
-
- if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) )
- {
- mergePluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
-
- // fix for MNG-2221 (assembly cache was not being populated for later reference):
- assembledPlugins.add( childPlugin );
- }
-
- // if we're processing this as an inheritance-based merge, and
- // the parent's flag is not set, then we need to
- // clear the inherited flag in the merge result.
- if ( handleAsInheritance && ( parentInherited == null ) )
- {
- parentPlugin.unsetInheritanceApplied();
- }
- }
-
- // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
- // since this list is a local one, and may have been modified during processing.
- List results =
- ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins, childContainer.getPlugins() );
-
- childContainer.setPlugins( results );
-
- childContainer.flushPluginMap();
- }
- }
+ throw new UnsupportedOperationException();
}
public static List orderAfterMerge( List merged, List highPrioritySource,
List lowPrioritySource )
{
- List results = new ArrayList<>();
-
- if ( !merged.isEmpty() )
- {
- results.addAll( merged );
- }
-
- List missingFromResults = new ArrayList<>();
-
- List> sources = new ArrayList<>();
-
- sources.add( highPrioritySource );
- sources.add( lowPrioritySource );
-
- for ( List source : sources )
- {
- for ( Plugin item : source )
- {
- if ( results.contains( item ) )
- {
- if ( !missingFromResults.isEmpty() )
- {
- int idx = results.indexOf( item );
-
- if ( idx < 0 )
- {
- idx = 0;
- }
-
- results.addAll( idx, missingFromResults );
-
- missingFromResults.clear();
- }
- }
- else
- {
- missingFromResults.add( item );
- }
- }
-
- if ( !missingFromResults.isEmpty() )
- {
- results.addAll( missingFromResults );
-
- missingFromResults.clear();
- }
- }
-
- return results;
+ throw new UnsupportedOperationException();
}
public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean handleAsInheritance )
{
- if ( ( child == null ) || ( parent == null ) )
- {
- // nothing to do.
- return;
- }
-
- if ( parent.isExtensions() )
- {
- child.setExtensions( true );
- }
-
- if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
- {
- child.setVersion( parent.getVersion() );
- }
-
- Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
- Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
-
- childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
-
- child.setConfiguration( childConfiguration );
-
- child.setDependencies( mergeDependencyList( child.getDependencies(), parent.getDependencies() ) );
-
- // from here to the end of the method is dealing with merging of the section.
- String parentInherited = parent.getInherited();
-
- boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited );
-
- List parentExecutions = parent.getExecutions();
-
- if ( ( parentExecutions != null ) && !parentExecutions.isEmpty() )
- {
- List mergedExecutions = new ArrayList<>();
-
- Map assembledExecutions = new TreeMap<>();
-
- Map childExecutions = child.getExecutionsAsMap();
-
- for ( PluginExecution parentExecution : parentExecutions )
- {
- String inherited = parentExecution.getInherited();
-
- boolean parentExecInherited =
- parentIsInherited && ( ( inherited == null ) || Boolean.parseBoolean( inherited ) );
-
- if ( !handleAsInheritance || parentExecInherited )
- {
- PluginExecution assembled = parentExecution;
-
- PluginExecution childExecution = childExecutions.get( parentExecution.getId() );
-
- if ( childExecution != null )
- {
- mergePluginExecutionDefinitions( childExecution, parentExecution );
-
- assembled = childExecution;
- }
- else if ( handleAsInheritance && ( parentInherited == null ) )
- {
- parentExecution.unsetInheritanceApplied();
- }
-
- assembledExecutions.put( assembled.getId(), assembled );
- mergedExecutions.add( assembled );
- }
- }
-
- for ( PluginExecution childExecution : child.getExecutions() )
- {
- if ( !assembledExecutions.containsKey( childExecution.getId() ) )
- {
- mergedExecutions.add( childExecution );
- }
- }
-
- child.setExecutions( mergedExecutions );
-
- child.flushExecutionMap();
- }
-
- }
-
- private static void mergePluginExecutionDefinitions( PluginExecution child, PluginExecution parent )
- {
- if ( child.getPhase() == null )
- {
- child.setPhase( parent.getPhase() );
- }
-
- List parentGoals = parent.getGoals();
- List childGoals = child.getGoals();
-
- List goals = new ArrayList<>();
-
- if ( ( childGoals != null ) && !childGoals.isEmpty() )
- {
- goals.addAll( childGoals );
- }
-
- if ( parentGoals != null )
- {
- for ( String goal : parentGoals )
- {
- if ( !goals.contains( goal ) )
- {
- goals.add( goal );
- }
- }
- }
-
- child.setGoals( goals );
-
- Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
- Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
-
- childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
-
- child.setConfiguration( childConfiguration );
- }
-
- public static List mergeRepositoryLists( List dominant, List recessive )
- {
-
- List repositories = new ArrayList<>( dominant );
-
- for ( Repository repository : recessive )
- {
- if ( !repositories.contains( repository ) )
- {
- repositories.add( repository );
- }
- }
-
- return repositories;
+ throw new UnsupportedOperationException();
}
public static void mergeFilterLists( List childFilters, List parentFilters )
{
- for ( String f : parentFilters )
- {
- if ( !childFilters.contains( f ) )
- {
- childFilters.add( f );
- }
- }
- }
-
- private static List mergeDependencyList( List child, List parent )
- {
- Map depsMap = new LinkedHashMap<>();
-
- if ( parent != null )
- {
- for ( Dependency dependency : parent )
- {
- depsMap.put( dependency.getManagementKey(), dependency );
- }
- }
-
- if ( child != null )
- {
- for ( Dependency dependency : child )
- {
- depsMap.put( dependency.getManagementKey(), dependency );
- }
- }
-
- return new ArrayList<>( depsMap.values() );
+ throw new UnsupportedOperationException();
}
}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
index 0113562cff..b6dd90d81b 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
@@ -19,729 +19,38 @@ package org.apache.maven.project.inheritance;
* under the License.
*/
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-
import org.apache.maven.model.Build;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.DeploymentRepository;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Extension;
import org.apache.maven.model.Model;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.Scm;
-import org.apache.maven.model.Site;
-import org.apache.maven.project.ModelUtils;
import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* DefaultModelInheritanceAssembler
*/
@Component( role = ModelInheritanceAssembler.class )
public class DefaultModelInheritanceAssembler
- implements ModelInheritanceAssembler
+ implements ModelInheritanceAssembler
{
- public void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance )
- {
- // The build has been set but we want to step in here and fill in
- // values that have not been set by the child.
-
- if ( childBuild.getSourceDirectory() == null )
- {
- childBuild.setSourceDirectory( parentBuild.getSourceDirectory() );
- }
-
- if ( childBuild.getScriptSourceDirectory() == null )
- {
- childBuild.setScriptSourceDirectory( parentBuild.getScriptSourceDirectory() );
- }
-
- if ( childBuild.getTestSourceDirectory() == null )
- {
- childBuild.setTestSourceDirectory( parentBuild.getTestSourceDirectory() );
- }
-
- if ( childBuild.getOutputDirectory() == null )
- {
- childBuild.setOutputDirectory( parentBuild.getOutputDirectory() );
- }
-
- if ( childBuild.getTestOutputDirectory() == null )
- {
- childBuild.setTestOutputDirectory( parentBuild.getTestOutputDirectory() );
- }
-
- // Extensions are accumulated
- mergeExtensionLists( childBuild, parentBuild );
-
- if ( childBuild.getDirectory() == null )
- {
- childBuild.setDirectory( parentBuild.getDirectory() );
- }
-
- if ( childBuild.getDefaultGoal() == null )
- {
- childBuild.setDefaultGoal( parentBuild.getDefaultGoal() );
- }
-
- if ( childBuild.getFinalName() == null )
- {
- childBuild.setFinalName( parentBuild.getFinalName() );
- }
-
- ModelUtils.mergeFilterLists( childBuild.getFilters(), parentBuild.getFilters() );
-
- List resources = childBuild.getResources();
- if ( ( resources == null ) || resources.isEmpty() )
- {
- childBuild.setResources( parentBuild.getResources() );
- }
-
- resources = childBuild.getTestResources();
- if ( ( resources == null ) || resources.isEmpty() )
- {
- childBuild.setTestResources( parentBuild.getTestResources() );
- }
-
- // Plugins are aggregated if Plugin.inherit != false
- ModelUtils.mergePluginLists( childBuild, parentBuild, handleAsInheritance );
-
- // Plugin management :: aggregate
- PluginManagement dominantPM = childBuild.getPluginManagement();
- PluginManagement recessivePM = parentBuild.getPluginManagement();
-
- if ( ( dominantPM == null ) && ( recessivePM != null ) )
- {
- // FIXME: Filter out the inherited == false stuff!
- childBuild.setPluginManagement( recessivePM );
- }
- else
- {
- ModelUtils.mergePluginLists( childBuild.getPluginManagement(), parentBuild.getPluginManagement(), false );
- }
- }
-
- private void assembleScmInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
- {
- if ( parent.getScm() != null )
- {
- Scm parentScm = parent.getScm();
-
- Scm childScm = child.getScm();
-
- if ( childScm == null )
- {
- childScm = new Scm();
-
- child.setScm( childScm );
- }
-
- if ( StringUtils.isEmpty( childScm.getConnection() ) && !StringUtils.isEmpty( parentScm.getConnection() ) )
- {
- childScm.setConnection(
- appendPath( parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
- }
-
- if ( StringUtils.isEmpty( childScm.getDeveloperConnection() )
- && !StringUtils.isEmpty( parentScm.getDeveloperConnection() ) )
- {
- childScm
- .setDeveloperConnection( appendPath( parentScm.getDeveloperConnection(), child.getArtifactId(),
- childPathAdjustment, appendPaths ) );
- }
-
- if ( StringUtils.isEmpty( childScm.getUrl() ) && !StringUtils.isEmpty( parentScm.getUrl() ) )
- {
- childScm.setUrl(
- appendPath( parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
- }
- }
- }
-
- public void copyModel( Model dest, Model source )
- {
- assembleModelInheritance( dest, source, null, false );
- }
-
+ @Override
public void assembleModelInheritance( Model child, Model parent, String childPathAdjustment )
{
- assembleModelInheritance( child, parent, childPathAdjustment, true );
+ throw new UnsupportedOperationException();
}
+ @Override
public void assembleModelInheritance( Model child, Model parent )
{
- assembleModelInheritance( child, parent, null, true );
+ throw new UnsupportedOperationException();
}
- private void assembleModelInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
+ @Override
+ public void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance )
{
- // cannot inherit from null parent.
- if ( parent == null )
- {
- return;
- }
-
- // Group id
- if ( child.getGroupId() == null )
- {
- child.setGroupId( parent.getGroupId() );
- }
-
- // version
- if ( child.getVersion() == null )
- {
- // The parent version may have resolved to something different, so we take what we asked for...
- // instead of - child.setVersion( parent.getVersion() );
-
- if ( child.getParent() != null )
- {
- child.setVersion( child.getParent().getVersion() );
- }
- }
-
- // inceptionYear
- if ( child.getInceptionYear() == null )
- {
- child.setInceptionYear( parent.getInceptionYear() );
- }
-
- // url
- if ( child.getUrl() == null )
- {
- if ( parent.getUrl() != null )
- {
- child.setUrl( appendPath( parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
- }
- else
- {
- child.setUrl( parent.getUrl() );
- }
- }
-
- assembleDistributionInheritance( child, parent, childPathAdjustment, appendPaths );
-
- // issueManagement
- if ( child.getIssueManagement() == null )
- {
- child.setIssueManagement( parent.getIssueManagement() );
- }
-
- // description
- if ( child.getDescription() == null )
- {
- child.setDescription( parent.getDescription() );
- }
-
- // Organization
- if ( child.getOrganization() == null )
- {
- child.setOrganization( parent.getOrganization() );
- }
-
- // Scm
- assembleScmInheritance( child, parent, childPathAdjustment, appendPaths );
-
- // ciManagement
- if ( child.getCiManagement() == null )
- {
- child.setCiManagement( parent.getCiManagement() );
- }
-
- // developers
- if ( child.getDevelopers().size() == 0 )
- {
- child.setDevelopers( parent.getDevelopers() );
- }
-
- // licenses
- if ( child.getLicenses().size() == 0 )
- {
- child.setLicenses( parent.getLicenses() );
- }
-
- // developers
- if ( child.getContributors().size() == 0 )
- {
- child.setContributors( parent.getContributors() );
- }
-
- // mailingLists
- if ( child.getMailingLists().size() == 0 )
- {
- child.setMailingLists( parent.getMailingLists() );
- }
-
- // Build
- assembleBuildInheritance( child, parent );
-
- assembleDependencyInheritance( child, parent );
-
- child.setRepositories( ModelUtils.mergeRepositoryLists( child.getRepositories(), parent.getRepositories() ) );
-// child.setPluginRepositories(
-// ModelUtils.mergeRepositoryLists( child.getPluginRepositories(), parent.getPluginRepositories() ) );
-
- assembleReportingInheritance( child, parent );
-
- assembleDependencyManagementInheritance( child, parent );
-
- Properties props = new Properties();
- props.putAll( parent.getProperties() );
- props.putAll( child.getProperties() );
-
- child.setProperties( props );
+ throw new UnsupportedOperationException();
}
- private void assembleDependencyManagementInheritance( Model child, Model parent )
+ @Override
+ public void copyModel( Model dest, Model source )
{
- DependencyManagement parentDepMgmt = parent.getDependencyManagement();
-
- DependencyManagement childDepMgmt = child.getDependencyManagement();
-
- if ( parentDepMgmt != null )
- {
- if ( childDepMgmt == null )
- {
- child.setDependencyManagement( parentDepMgmt );
- }
- else
- {
- List childDeps = childDepMgmt.getDependencies();
-
- Map mappedChildDeps = new TreeMap<>();
- for ( Dependency dep : childDeps )
- {
- mappedChildDeps.put( dep.getManagementKey(), dep );
- }
-
- for ( Dependency dep : parentDepMgmt.getDependencies() )
- {
- if ( !mappedChildDeps.containsKey( dep.getManagementKey() ) )
- {
- childDepMgmt.addDependency( dep );
- }
- }
- }
- }
+ throw new UnsupportedOperationException();
}
-
- private void assembleReportingInheritance( Model child, Model parent )
- {
- // Reports :: aggregate
- Reporting childReporting = child.getReporting();
- Reporting parentReporting = parent.getReporting();
-
- if ( parentReporting != null )
- {
- if ( childReporting == null )
- {
- childReporting = new Reporting();
- child.setReporting( childReporting );
- }
-
- childReporting.setExcludeDefaults( parentReporting.isExcludeDefaults() );
-
- if ( StringUtils.isEmpty( childReporting.getOutputDirectory() ) )
- {
- childReporting.setOutputDirectory( parentReporting.getOutputDirectory() );
- }
-
- mergeReportPluginLists( childReporting, parentReporting, true );
- }
- }
-
- private static void mergeReportPluginLists( Reporting child, Reporting parent, boolean handleAsInheritance )
- {
- if ( ( child == null ) || ( parent == null ) )
- {
- // nothing to do.
- return;
- }
-
- List parentPlugins = parent.getPlugins();
-
- if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
- {
- Map assembledPlugins = new TreeMap<>();
-
- Map childPlugins = child.getReportPluginsAsMap();
-
- for ( ReportPlugin parentPlugin : parentPlugins )
- {
- String parentInherited = parentPlugin.getInherited();
-
- if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ) )
- {
-
- ReportPlugin assembledPlugin = parentPlugin;
-
- ReportPlugin childPlugin = childPlugins.get( parentPlugin.getKey() );
-
- if ( childPlugin != null )
- {
- assembledPlugin = childPlugin;
-
- mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
- }
-
- if ( handleAsInheritance && ( parentInherited == null ) )
- {
- assembledPlugin.unsetInheritanceApplied();
- }
-
- assembledPlugins.put( assembledPlugin.getKey(), assembledPlugin );
- }
- }
-
- for ( ReportPlugin childPlugin : childPlugins.values() )
- {
- if ( !assembledPlugins.containsKey( childPlugin.getKey() ) )
- {
- assembledPlugins.put( childPlugin.getKey(), childPlugin );
- }
- }
-
- child.setPlugins( new ArrayList<>( assembledPlugins.values() ) );
-
- child.flushReportPluginMap();
- }
- }
-
- private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
- {
- List parentReports = parent.getReports();
- List