diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index fa3b3e4fc4..29f86b8047 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -71,6 +71,7 @@ import org.apache.maven.model.building.StringModelSource; import org.apache.maven.model.building.TransformerContext; import org.apache.maven.model.resolution.ModelResolver; import org.apache.maven.repository.internal.ArtifactDescriptorUtils; +import org.apache.maven.repository.internal.DefaultModelCache; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.util.Os; import org.codehaus.plexus.util.StringUtils; @@ -92,9 +93,6 @@ public class DefaultProjectBuilder implements ProjectBuilder { - public static final String DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY = - "maven.defaultProjectBuilder.disableGlobalModelCache"; - @Inject private Logger logger; @@ -119,8 +117,6 @@ public class DefaultProjectBuilder @Inject private ProjectDependenciesResolver dependencyResolver; - private final ReactorModelCache modelCache = new ReactorModelCache(); - // ---------------------------------------------------------------------- // MavenProjectBuilder Implementation // ---------------------------------------------------------------------- @@ -130,12 +126,7 @@ public class DefaultProjectBuilder throws ProjectBuildingException { return build( pomFile, new FileModelSource( pomFile ), - new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null ) ); - } - - private boolean useGlobalModelCache() - { - return !Boolean.getBoolean( DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY ); + new InternalConfig( request, null, null ) ); } @Override @@ -143,7 +134,7 @@ public class DefaultProjectBuilder throws ProjectBuildingException { return build( null, modelSource, - new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null ) ); + new InternalConfig( request, null, null ) ); } private ProjectBuildingResult build( File pomFile, ModelSource modelSource, InternalConfig config ) @@ -288,7 +279,7 @@ public class DefaultProjectBuilder request.setUserProperties( configuration.getUserProperties() ); request.setBuildStartTime( configuration.getBuildStartTime() ); request.setModelResolver( resolver ); - request.setModelCache( config.modelCache ); + request.setModelCache( DefaultModelCache.newInstance( config.session ) ); request.setTransformerContextBuilder( config.transformerContextBuilder ); return request; @@ -309,7 +300,7 @@ public class DefaultProjectBuilder pomArtifact = ArtifactDescriptorUtils.toPomArtifact( pomArtifact ); InternalConfig config = - new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null ); + new InternalConfig( request, null, null ); boolean localProject; @@ -382,8 +373,7 @@ public class DefaultProjectBuilder final ReactorModelPool modelPool = poolBuilder.build(); InternalConfig config = - new InternalConfig( request, modelPool, useGlobalModelCache() ? getModelCache() : new ReactorModelCache(), - modelBuilder.newTransformerContextBuilder() ); + new InternalConfig( request, modelPool, modelBuilder.newTransformerContextBuilder() ); Map projectIndex = new HashMap<>( 256 ); @@ -1023,16 +1013,13 @@ public class DefaultProjectBuilder private final ReactorModelPool modelPool; - private final ReactorModelCache modelCache; - private final TransformerContextBuilder transformerContextBuilder; - InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool, ReactorModelCache modelCache, + InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool, TransformerContextBuilder transformerContextBuilder ) { this.request = request; this.modelPool = modelPool; - this.modelCache = modelCache; this.transformerContextBuilder = transformerContextBuilder; session = @@ -1044,9 +1031,4 @@ public class DefaultProjectBuilder } - private ReactorModelCache getModelCache() - { - return this.modelCache; - } - } diff --git a/maven-core/src/main/java/org/apache/maven/project/ReactorModelCache.java b/maven-core/src/main/java/org/apache/maven/project/ReactorModelCache.java deleted file mode 100644 index 10ca8786bf..0000000000 --- a/maven-core/src/main/java/org/apache/maven/project/ReactorModelCache.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.apache.maven.project; - -/* - * 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.building.Source; -import org.apache.maven.model.building.ModelCache; - -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * A simple model cache used to accelerate model building during a reactor build. - * - * @author Benjamin Bentmann - */ -class ReactorModelCache - implements ModelCache -{ - - private final Map models = new ConcurrentHashMap<>( 256 ); - - @Override - public Object get( String groupId, String artifactId, String version, String tag ) - { - return models.get( new GavCacheKey( groupId, artifactId, version, tag ) ); - } - - @Override - public void put( String groupId, String artifactId, String version, String tag, Object data ) - { - models.put( new GavCacheKey( groupId, artifactId, version, tag ), data ); - } - - @Override - public Object get( Source source, String tag ) - { - return models.get( new SourceCacheKey( source, tag ) ); - } - - @Override - public void put( Source source, String tag, Object data ) - { - models.put( new SourceCacheKey( source, tag ), data ); - } - - private static final class GavCacheKey - { - - private final String groupId; - - private final String artifactId; - - private final String version; - - private final String tag; - - private final int hashCode; - - GavCacheKey( String groupId, String artifactId, String version, String tag ) - { - this.groupId = ( groupId != null ) ? groupId : ""; - this.artifactId = ( artifactId != null ) ? artifactId : ""; - this.version = ( version != null ) ? version : ""; - this.tag = ( tag != null ) ? tag : ""; - this.hashCode = Objects.hash( groupId, artifactId, version, tag ); - } - - @Override - public boolean equals( Object obj ) - { - if ( this == obj ) - { - return true; - } - - if ( !( obj instanceof GavCacheKey ) ) - { - return false; - } - - GavCacheKey that = (GavCacheKey) obj; - - return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) - && version.equals( that.version ) && tag.equals( that.tag ); - } - - @Override - public int hashCode() - { - return hashCode; - } - } - - private static final class SourceCacheKey - { - private final Source source; - - private final String tag; - - private final int hashCode; - - SourceCacheKey( Source source, String tag ) - { - this.source = source; - this.tag = tag; - this.hashCode = Objects.hash( source, tag ); - } - - @Override - public int hashCode() - { - return hashCode; - } - - @Override - public boolean equals( Object obj ) - { - if ( this == obj ) - { - return true; - } - if ( !( obj instanceof SourceCacheKey ) ) - { - return false; - } - - SourceCacheKey other = (SourceCacheKey) obj; - if ( !Objects.equals( this.source, other.source ) ) - { - return false; - } - - if ( !Objects.equals( this.tag, other.tag ) ) - { - return false; - } - - return true; - } - } - -} diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index f23132ce86..e2babbf5a9 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -150,7 +150,6 @@ public class ProjectBuilderTest @Test public void testReadModifiedPoms() throws Exception { - String initialValue = System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, Boolean.toString( true ) ); // TODO a similar test should be created to test the dependency management (basically all usages // of DefaultModelBuilder.getCache() are affected by MNG-6530 @@ -177,14 +176,6 @@ public class ProjectBuilderTest } finally { - if ( initialValue == null ) - { - System.clearProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY ); - } - else - { - System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, initialValue ); - } FileUtils.deleteDirectory( tempDir.toFile() ); } } diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index 792a831500..c217c9ea66 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -83,6 +83,7 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti import org.codehaus.plexus.logging.LoggerManager; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.eclipse.aether.DefaultRepositoryCache; import org.eclipse.aether.transfer.TransferListener; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; @@ -975,6 +976,11 @@ public class MavenCli { MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request ); + if ( cliRequest.request.getRepositoryCache() == null ) + { + cliRequest.request.setRepositoryCache( new DefaultRepositoryCache() ); + } + eventSpyDispatcher.onEvent( request ); MavenExecutionResult result = maven.execute( request ); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index 7233cf5f76..afde52a648 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java @@ -22,7 +22,6 @@ package org.apache.maven.model.building; import static org.apache.maven.model.building.Result.error; import static org.apache.maven.model.building.Result.newResult; -import org.apache.maven.artifact.versioning.ArtifactVersion; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -52,21 +51,15 @@ import org.apache.maven.building.Source; import org.apache.maven.feature.Features; import org.apache.maven.model.Activation; import org.apache.maven.model.Build; -import org.apache.maven.model.BuildBase; -import org.apache.maven.model.CiManagement; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.InputLocation; import org.apache.maven.model.InputSource; import org.apache.maven.model.Model; -import org.apache.maven.model.ModelBase; import org.apache.maven.model.Parent; import org.apache.maven.model.Plugin; -import org.apache.maven.model.PluginContainer; import org.apache.maven.model.PluginManagement; import org.apache.maven.model.Profile; -import org.apache.maven.model.ReportPlugin; -import org.apache.maven.model.Reporting; import org.apache.maven.model.Repository; import org.apache.maven.model.building.ModelProblem.Severity; import org.apache.maven.model.building.ModelProblem.Version; @@ -275,7 +268,6 @@ public class DefaultModelBuilder return build( request, new LinkedHashSet<>() ); } - @SuppressWarnings( "checkstyle:methodlength" ) protected ModelBuildingResult build( ModelBuildingRequest request, Collection importIds ) throws ModelBuildingException { @@ -388,7 +380,7 @@ public class DefaultModelBuilder List lineage = new ArrayList<>(); - for ( ModelData currentData = resultData; currentData != null; ) + for ( ModelData currentData = resultData; ; ) { String modelId = currentData.getId(); result.addModelId( modelId ); @@ -586,18 +578,38 @@ public class DefaultModelBuilder } } - @SuppressWarnings( "checkstyle:methodlength" ) private Model readFileModel( ModelBuildingRequest request, DefaultModelProblemCollector problems ) throws ModelBuildingException { ModelSource modelSource = request.getModelSource(); - Model model = getModelFromCache( modelSource, request.getModelCache() ); - if ( model != null ) + Model model = fromCache( request.getModelCache(), modelSource, ModelCacheTag.FILE ); + if ( model == null ) { - return model; + model = doReadFileModel( modelSource, request, problems ); + + intoCache( request.getModelCache(), modelSource, ModelCacheTag.FILE, model ); } + if ( modelSource instanceof FileModelSource ) + { + if ( request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder ) + { + DefaultTransformerContextBuilder contextBuilder = + (DefaultTransformerContextBuilder) request.getTransformerContextBuilder(); + contextBuilder.putSource( getGroupId( model ), model.getArtifactId(), modelSource ); + } + } + + return model; + } + + @SuppressWarnings( "checkstyle:methodlength" ) + private Model doReadFileModel( ModelSource modelSource, ModelBuildingRequest request, + DefaultModelProblemCollector problems ) + throws ModelBuildingException + { + Model model; problems.setSource( modelSource.getLocation() ); try { @@ -640,18 +652,10 @@ public class DefaultModelBuilder throw e; } - if ( modelSource instanceof FileModelSource ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ) - .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); - } - else - { - problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) - .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); - } + Severity severity = ( modelSource instanceof FileModelSource ) ? Severity.ERROR : Severity.WARNING; + problems.add( new ModelProblemCollectorRequest( severity, Version.V20 ) + .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) + .setException( e ) ); } if ( source != null ) @@ -700,17 +704,6 @@ public class DefaultModelBuilder throw problems.newModelBuildingException(); } - intoCache( request.getModelCache(), modelSource, ModelCacheTag.FILE, model ); - if ( modelSource instanceof FileModelSource ) - { - if ( request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder ) - { - DefaultTransformerContextBuilder contextBuilder = - (DefaultTransformerContextBuilder) request.getTransformerContextBuilder(); - contextBuilder.putSource( getGroupId( model ), model.getArtifactId(), modelSource ); - } - } - return model; } @@ -722,7 +715,7 @@ public class DefaultModelBuilder ModelData cachedData = fromCache( request.getModelCache(), modelSource, ModelCacheTag.RAW ); if ( cachedData != null ) { - return cachedData.getModel(); + return cachedData.getModel(); } Model rawModel; @@ -774,37 +767,11 @@ public class DefaultModelBuilder String version = getVersion( rawModel ); ModelData modelData = new ModelData( modelSource, rawModel, groupId, artifactId, version ); - intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, modelData ); intoCache( request.getModelCache(), modelSource, ModelCacheTag.RAW, modelData ); return rawModel; } - private Model getModelFromCache( Source source, ModelCache cache ) - { - Model model; - if ( source instanceof ArtifactModelSource ) - { - ArtifactModelSource artifactModelSource = ( ArtifactModelSource ) source; - ModelData modelData = fromCache( cache, artifactModelSource.getGroupId(), - artifactModelSource.getArtifactId(), - artifactModelSource.getVersion(), ModelCacheTag.RAW ); - if ( modelData != null ) - { - model = modelData.getModel(); - } - else - { - model = null; - } - } - else - { - model = fromCache( cache, source, ModelCacheTag.FILE ); - } - return model; - } - private String getGroupId( Model model ) { String groupId = model.getGroupId(); @@ -1014,75 +981,21 @@ public class DefaultModelBuilder ModelData parentData = null; Parent parent = childModel.getParent(); - if ( parent != null ) { - Source expectedParentSource = getParentPomFile( childModel, childSource ); - - if ( expectedParentSource != null ) - { - ModelData candidateData = readParentLocally( childModel, childSource, request, result, problems ); - - if ( candidateData != null ) - { - /* - * NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved, - * the child's GAV should match with that parent, too. If it doesn't, we ignore the cache and - * resolve externally, to mimic the behavior if the cache didn't exist in the first place. - * Otherwise, the cache would obscure a bad POM. - */ - try - { - VersionRange parentVersion = VersionRange.createFromVersionSpec( parent.getVersion() ); - ArtifactVersion actualVersion = new DefaultArtifactVersion( candidateData.getVersion() ); - - if ( parent.getGroupId().equals( candidateData.getGroupId() ) - && parent.getArtifactId().equals( candidateData.getArtifactId() ) - && parentVersion.containsVersion( actualVersion ) ) - { - parentData = candidateData; - } - } - catch ( InvalidVersionSpecificationException e ) - { - // This should already been blocked during validation - } - } - } - + parentData = readParentLocally( childModel, childSource, request, result, problems ); if ( parentData == null ) { - ModelData candidateData = fromCache( request.getModelCache(), - parent.getGroupId(), parent.getArtifactId(), - parent.getVersion(), ModelCacheTag.RAW ); - - - if ( candidateData != null && candidateData.getSource() instanceof ArtifactModelSource ) - { - // ArtifactModelSource means repositorySource - parentData = candidateData; - } - else - { - parentData = readParentExternally( childModel, request, result, problems ); - - intoCache( request.getModelCache(), - parentData.getGroupId(), parentData.getArtifactId(), - parentData.getVersion(), ModelCacheTag.RAW, parentData ); - } + parentData = readParentExternally( childModel, request, result, problems ); } - - if ( parentData != null ) + + Model parentModel = parentData.getModel(); + if ( !"pom".equals( parentModel.getPackaging() ) ) { - Model parentModel = parentData.getModel(); - - if ( !"pom".equals( parentModel.getPackaging() ) ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) - + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ) - .setLocation( parentModel.getLocation( "packaging" ) ) ); - } + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) + + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ) + .setLocation( parentModel.getLocation( "packaging" ) ) ); } } @@ -1106,14 +1019,8 @@ public class DefaultModelBuilder return null; } - ModelBuildingRequest candidateBuildRequest = new FilterModelBuildingRequest( request ) - { - @Override - public ModelSource getModelSource() - { - return candidateSource; - } - }; + ModelBuildingRequest candidateBuildRequest = new DefaultModelBuildingRequest( request ) + .setModelSource( candidateSource ); candidateModel = readRawModel( candidateBuildRequest, problems ); } @@ -1127,7 +1034,7 @@ public class DefaultModelBuilder catch ( UnresolvableModelException e ) { problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) // - .setMessage( e.getMessage() ).setLocation( parent.getLocation( "" ) ).setException( e ) ); + .setMessage( e.getMessage() ).setLocation( parent.getLocation( "" ) ).setException( e ) ); throw problems.newModelBuildingException(); } if ( candidateModel == null ) @@ -1143,11 +1050,7 @@ public class DefaultModelBuilder // before because with parents as ranges it will never work in this scenario. // - String groupId = candidateModel.getGroupId(); - if ( groupId == null && candidateModel.getParent() != null ) - { - groupId = candidateModel.getParent().getGroupId(); - } + String groupId = getGroupId( candidateModel ); String artifactId = candidateModel.getArtifactId(); if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null @@ -1169,11 +1072,7 @@ public class DefaultModelBuilder return null; } - String version = candidateModel.getVersion(); - if ( version == null && candidateModel.getParent() != null ) - { - version = candidateModel.getParent().getVersion(); - } + String version = getVersion( candidateModel ); if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) ) { try @@ -1303,25 +1202,10 @@ public class DefaultModelBuilder } int validationLevel = Math.min( request.getValidationLevel(), ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ); - ModelBuildingRequest lenientRequest = new FilterModelBuildingRequest( request ) - { - @Override - public int getValidationLevel() - { - return validationLevel; - } - - @Override - public ModelSource getModelSource() - { - return modelSource; - } - @Override - public Model getFileModel() - { - return null; - } - }; + ModelBuildingRequest lenientRequest = new DefaultModelBuildingRequest( request ) + .setValidationLevel( validationLevel ) + .setFileModel( null ) + .setModelSource( modelSource ); Model parentModel = readRawModel( lenientRequest, problems ); @@ -1358,7 +1242,6 @@ public class DefaultModelBuilder return superPomProvider.getSuperModel( "4.0.0" ).clone(); } - @SuppressWarnings( "checkstyle:methodlength" ) private void importDependencyManagement( Model model, ModelBuildingRequest request, DefaultModelProblemCollector problems, Collection importIds ) { @@ -1373,11 +1256,6 @@ public class DefaultModelBuilder importIds.add( importing ); - final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver(); - final ModelResolver modelResolver = request.getModelResolver(); - - ModelBuildingRequest importRequest = null; - List importMgmts = null; for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); ) @@ -1391,148 +1269,18 @@ public class DefaultModelBuilder it.remove(); - String groupId = dependency.getGroupId(); - String artifactId = dependency.getArtifactId(); - String version = dependency.getVersion(); + DependencyManagement importMgmt = loadDependencyManagement( model, request, problems, + dependency, importIds ); - if ( groupId == null || groupId.length() <= 0 ) + if ( importMgmt != null ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); - continue; - } - if ( artifactId == null || artifactId.length() <= 0 ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); - continue; - } - if ( version == null || version.length() <= 0 ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.version' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); - continue; - } - - String imported = groupId + ':' + artifactId + ':' + version; - - if ( importIds.contains( imported ) ) - { - String message = "The dependencies of type=pom and with scope=import form a cycle: "; - for ( String modelId : importIds ) + if ( importMgmts == null ) { - message += modelId + " -> "; - } - message += imported; - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); - - continue; - } - - DependencyManagement importMgmt = fromCache( request.getModelCache(), groupId, artifactId, version, - ModelCacheTag.IMPORT ); - - if ( importMgmt == null ) - { - if ( workspaceResolver == null && modelResolver == null ) - { - throw new NullPointerException( String.format( - "request.workspaceModelResolver and request.modelResolver cannot be null" - + " (parent POM %s and POM %s)", - ModelProblemUtils.toId( groupId, artifactId, version ), - ModelProblemUtils.toSourceHint( model ) ) ); + importMgmts = new ArrayList<>(); } - Model importModel = null; - if ( workspaceResolver != null ) - { - try - { - importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version ); - } - catch ( UnresolvableModelException e ) - { - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( e.getMessage() ).setException( e ) ); - continue; - } - } - - // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) - if ( importModel == null ) - { - final ModelSource importSource; - try - { - importSource = modelResolver.resolveModel( dependency ); - } - catch ( UnresolvableModelException e ) - { - StringBuilder buffer = new StringBuilder( 256 ); - buffer.append( "Non-resolvable import POM" ); - if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) - { - buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); - } - buffer.append( ": " ).append( e.getMessage() ); - - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) ) - .setException( e ) ); - continue; - } - - if ( importRequest == null ) - { - importRequest = new DefaultModelBuildingRequest(); - importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); - importRequest.setModelCache( request.getModelCache() ); - importRequest.setSystemProperties( request.getSystemProperties() ); - importRequest.setUserProperties( request.getUserProperties() ); - importRequest.setLocationTracking( request.isLocationTracking() ); - } - - importRequest.setModelSource( importSource ); - importRequest.setModelResolver( modelResolver.newCopy() ); - - final ModelBuildingResult importResult; - try - { - importResult = build( importRequest, importIds ); - } - catch ( ModelBuildingException e ) - { - problems.addAll( e.getProblems() ); - continue; - } - - problems.addAll( importResult.getProblems() ); - - importModel = importResult.getEffectiveModel(); - } - - importMgmt = importModel.getDependencyManagement(); - - if ( importMgmt == null ) - { - importMgmt = new DependencyManagement(); - } - - intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + importMgmts.add( importMgmt ); } - - if ( importMgmts == null ) - { - importMgmts = new ArrayList<>(); - } - - importMgmts.add( importMgmt ); } importIds.remove( importing ); @@ -1540,12 +1288,166 @@ public class DefaultModelBuilder dependencyManagementImporter.importManagement( model, importMgmts, request, problems ); } + private DependencyManagement loadDependencyManagement( Model model, ModelBuildingRequest request, + DefaultModelProblemCollector problems, + Dependency dependency, + Collection importIds ) + { + String groupId = dependency.getGroupId(); + String artifactId = dependency.getArtifactId(); + String version = dependency.getVersion(); + + if ( groupId == null || groupId.length() <= 0 ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); + return null; + } + if ( artifactId == null || artifactId.length() <= 0 ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); + return null; + } + if ( version == null || version.length() <= 0 ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "'dependencyManagement.dependencies.dependency.version' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); + return null; + } + + String imported = groupId + ':' + artifactId + ':' + version; + + if ( importIds.contains( imported ) ) + { + String message = "The dependencies of type=pom and with scope=import form a cycle: "; + for ( String modelId : importIds ) + { + message += modelId + " -> "; + } + message += imported; + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); + + return null; + } + + DependencyManagement importMgmt = fromCache( request.getModelCache(), groupId, artifactId, version, + ModelCacheTag.IMPORT ); + if ( importMgmt == null ) + { + importMgmt = doLoadDependencyManagement( model, request, problems, dependency, + groupId, artifactId, version, importIds ); + if ( importMgmt != null ) + { + intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + } + } + + return importMgmt; + } + + @SuppressWarnings( "checkstyle:parameternumber" ) + private DependencyManagement doLoadDependencyManagement( Model model, ModelBuildingRequest request, + DefaultModelProblemCollector problems, + Dependency dependency, + String groupId, + String artifactId, + String version, + Collection importIds ) + { + DependencyManagement importMgmt; + final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver(); + final ModelResolver modelResolver = request.getModelResolver(); + if ( workspaceResolver == null && modelResolver == null ) + { + throw new NullPointerException( String.format( + "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)", + ModelProblemUtils.toId( groupId, artifactId, version ), + ModelProblemUtils.toSourceHint( model ) ) ); + } + + Model importModel = null; + if ( workspaceResolver != null ) + { + try + { + importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version ); + } + catch ( UnresolvableModelException e ) + { + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) + .setMessage( e.getMessage() ).setException( e ) ); + return null; + } + } + + // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) + if ( importModel == null ) + { + final ModelSource importSource; + try + { + importSource = modelResolver.resolveModel( dependency ); + } + catch ( UnresolvableModelException e ) + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Non-resolvable import POM" ); + if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) + { + buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); + } + buffer.append( ": " ).append( e.getMessage() ); + + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) ) + .setException( e ) ); + return null; + } + + final ModelBuildingResult importResult; + try + { + ModelBuildingRequest importRequest = new DefaultModelBuildingRequest( request ) + .setTwoPhaseBuilding( false ) + .setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ) + .setModelSource( importSource ) + .setModelResolver( modelResolver.newCopy() ); + + importResult = build( importRequest, importIds ); + } + catch ( ModelBuildingException e ) + { + problems.addAll( e.getProblems() ); + return null; + } + + problems.addAll( importResult.getProblems() ); + + importModel = importResult.getEffectiveModel(); + } + + importMgmt = importModel.getDependencyManagement(); + + if ( importMgmt == null ) + { + importMgmt = new DependencyManagement(); + } + return importMgmt; + } + private void intoCache( ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag tag, T data ) { if ( modelCache != null ) { - modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) ); + modelCache.put( groupId, artifactId, version, tag, data ); } } @@ -1553,7 +1455,7 @@ public class DefaultModelBuilder { if ( modelCache != null ) { - modelCache.put( source, tag.getName(), tag.intoCache( data ) ); + modelCache.put( source, tag, data ); } } @@ -1562,11 +1464,7 @@ public class DefaultModelBuilder { if ( modelCache != null ) { - Object data = modelCache.get( groupId, artifactId, version, tag.getName() ); - if ( data != null ) - { - return tag.fromCache( tag.getType().cast( data ) ); - } + return modelCache.get( groupId, artifactId, version, tag ); } return null; } @@ -1575,11 +1473,7 @@ public class DefaultModelBuilder { if ( modelCache != null ) { - Object data = modelCache.get( source, tag.getName() ); - if ( data != null ) - { - return tag.fromCache( tag.getType().cast( data ) ); - } + return modelCache.get( source, tag ); } return null; } @@ -1633,158 +1527,6 @@ public class DefaultModelBuilder } } - /** - * As long as Maven controls the BuildPomXMLFilter, the entities that need merging are known. - * All others can simply be copied from source to target to restore the locationTracker - * - * @author Robert Scholte - * @since 4.0.0 - */ - class FileToRawModelMerger extends ModelMerger - { - @Override - protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - - @Override - protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source, - boolean sourceDominant, Map context ) - { - Iterator sourceIterator = source.getDependencies().iterator(); - target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, - context ) ); - } - - @Override - protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant, - Map context ) - { - Iterator sourceIterator = source.getProfiles().iterator(); - target.getProfiles().stream().forEach( t -> mergeProfile( t, sourceIterator.next(), sourceDominant, - context ) ); - } - - @Override - protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant, - Map context ) - { - Iterator sourceIterator = source.getDependencies().iterator(); - target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, - context ) ); - } - - @Override - protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant, - Map context ) - { - target.setPluginRepositories( source.getPluginRepositories() ); - } - - @Override - protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant, - Map context ) - { - Iterator sourceIterator = source.getDependencies().iterator(); - target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, - context ) ); - } - - @Override - protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant, - Map context ) - { - // don't merge - } - - @Override - protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source, - boolean sourceDominant, Map context ) - { - // don't merge - } - } - /** * Builds up the transformer context. * After the buildplan is ready, the build()-method returns the immutable context useful during distribution. @@ -1841,15 +1583,8 @@ public class DefaultModelBuilder { try { - ModelBuildingRequest gaBuildingRequest = new FilterModelBuildingRequest( request ) - { - @Override - public ModelSource getModelSource() - { - return (ModelSource) source; - } - - }; + ModelBuildingRequest gaBuildingRequest = new DefaultModelBuildingRequest( request ) + .setModelSource( (ModelSource) source ); return readRawModel( gaBuildingRequest, problems ); } catch ( ModelBuildingException e ) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java index a012786341..379b5e7e1c 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java @@ -102,6 +102,7 @@ public class DefaultModelBuildingRequest setModelResolver( request.getModelResolver() ); setModelBuildingListener( request.getModelBuildingListener() ); setModelCache( request.getModelCache() ); + setWorkspaceModelResolver( request.getWorkspaceModelResolver() ); setTransformerContextBuilder( request.getTransformerContextBuilder() ); } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java new file mode 100644 index 0000000000..f697d771d0 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java @@ -0,0 +1,190 @@ +package org.apache.maven.model.building; + +/* + * 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.Iterator; +import java.util.Map; + +import org.apache.maven.model.Build; +import org.apache.maven.model.BuildBase; +import org.apache.maven.model.CiManagement; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.DependencyManagement; +import org.apache.maven.model.Model; +import org.apache.maven.model.ModelBase; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginContainer; +import org.apache.maven.model.Profile; +import org.apache.maven.model.ReportPlugin; +import org.apache.maven.model.Reporting; +import org.apache.maven.model.merge.ModelMerger; + +/** + * As long as Maven controls the BuildPomXMLFilter, the entities that need merging are known. + * All others can simply be copied from source to target to restore the locationTracker + * + * @author Robert Scholte + * @since 4.0.0 + */ +class FileToRawModelMerger extends ModelMerger +{ + + @Override + protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + + @Override + protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source, + boolean sourceDominant, Map context ) + { + Iterator sourceIterator = source.getDependencies().iterator(); + target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, + context ) ); + } + + @Override + protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant, + Map context ) + { + Iterator sourceIterator = source.getProfiles().iterator(); + target.getProfiles().stream().forEach( t -> mergeProfile( t, sourceIterator.next(), sourceDominant, + context ) ); + } + + @Override + protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant, + Map context ) + { + Iterator sourceIterator = source.getDependencies().iterator(); + target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, + context ) ); + } + + @Override + protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant, + Map context ) + { + target.setPluginRepositories( source.getPluginRepositories() ); + } + + @Override + protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant, + Map context ) + { + Iterator sourceIterator = source.getDependencies().iterator(); + target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant, + context ) ); + } + + @Override + protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant, + Map context ) + { + // don't merge + } + + @Override + protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source, + boolean sourceDominant, Map context ) + { + // don't merge + } +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java index 3962fe0bfa..b44e8a40f1 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java @@ -82,4 +82,60 @@ public interface ModelCache */ Object get( String groupId, String artifactId, String version, String tag ); + /** + * Puts the specified data into the cache. + * + * @param path The path of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @param data The data to store in the cache, must not be {@code null}. + * @since 3.7.0 + */ + default void put( Source path, ModelCacheTag tag, T data ) + { + put( path, tag.getName(), tag.intoCache( data ) ); + } + + /** + * Gets the specified data from the cache. + * + * @param path The path of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @return The requested data or {@code null} if none was present in the cache. + * @since 3.7.0 + */ + default T get( Source path, ModelCacheTag tag ) + { + Object obj = get( path, tag.getName() ); + return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null; + } + + /** + * Puts the specified data into the cache. + * + * @param groupId The group id of the cache record, must not be {@code null}. + * @param artifactId The artifact id of the cache record, must not be {@code null}. + * @param version The version of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @param data The data to store in the cache, must not be {@code null}. + */ + default void put( String groupId, String artifactId, String version, ModelCacheTag tag, T data ) + { + put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) ); + } + + /** + * Gets the specified data from the cache. + * + * @param groupId The group id of the cache record, must not be {@code null}. + * @param artifactId The artifact id of the cache record, must not be {@code null}. + * @param version The version of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @return The requested data or {@code null} if none was present in the cache. + */ + default T get( String groupId, String artifactId, String version, ModelCacheTag tag ) + { + Object obj = get( groupId, artifactId, version, tag.getName() ); + return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null; + } + } diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java index 9d5301411c..286664ce14 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.model.building.DefaultModelBuilder.FileToRawModelMerger; import org.apache.maven.model.merge.ModelMerger; import org.junit.jupiter.api.Test; diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java index 86edf16fff..339bc08b8b 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java @@ -19,8 +19,12 @@ package org.apache.maven.repository.internal; * under the License. */ +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.maven.building.Source; import org.apache.maven.model.building.ModelCache; -import org.eclipse.aether.RepositoryCache; import org.eclipse.aether.RepositorySystemSession; /** @@ -28,68 +32,107 @@ import org.eclipse.aether.RepositorySystemSession; * * @author Benjamin Bentmann */ -class DefaultModelCache +public class DefaultModelCache implements ModelCache { - private final RepositorySystemSession session; + private static final String KEY = DefaultModelCache.class.getName(); - private final RepositoryCache cache; + private final Map cache; public static ModelCache newInstance( RepositorySystemSession session ) { + Map cache; if ( session.getCache() == null ) { - return null; + cache = new ConcurrentHashMap<>(); } else { - return new DefaultModelCache( session ); + cache = ( Map ) session.getCache().get( session, KEY ); + if ( cache == null ) + { + cache = new ConcurrentHashMap<>(); + session.getCache().put( session, KEY, cache ); + } } + return new DefaultModelCache( cache ); } - private DefaultModelCache( RepositorySystemSession session ) + private DefaultModelCache( Map cache ) { - this.session = session; - this.cache = session.getCache(); + this.cache = cache; + } + + public Object get( Source path, String tag ) + { + return get( new SourceCacheKey( path, tag ) ); + } + + public void put( Source path, String tag, Object data ) + { + put( new SourceCacheKey( path, tag ), data ); } public Object get( String groupId, String artifactId, String version, String tag ) { - return cache.get( session, new Key( groupId, artifactId, version, tag ) ); + return get( new GavCacheKey( groupId, artifactId, version, tag ) ); } public void put( String groupId, String artifactId, String version, String tag, Object data ) { - cache.put( session, new Key( groupId, artifactId, version, tag ), data ); + put( new GavCacheKey( groupId, artifactId, version, tag ), data ); } - static class Key + protected Object get( Object key ) + { + return cache.get( key ); + } + + protected void put( Object key, Object data ) + { + cache.put( key, data ); + } + + static class GavCacheKey { - private final String groupId; - - private final String artifactId; - - private final String version; + private final String gav; private final String tag; private final int hash; - Key( String groupId, String artifactId, String version, String tag ) + GavCacheKey( String groupId, String artifactId, String version, String tag ) { - this.groupId = groupId; - this.artifactId = artifactId; - this.version = version; - this.tag = tag; + this( gav( groupId, artifactId, version ), tag ); + } - int h = 17; - h = h * 31 + this.groupId.hashCode(); - h = h * 31 + this.artifactId.hashCode(); - h = h * 31 + this.version.hashCode(); - h = h * 31 + this.tag.hashCode(); - hash = h; + GavCacheKey( String gav, String tag ) + { + this.gav = gav; + this.tag = tag; + this.hash = Objects.hash( gav, tag ); + } + + private static String gav( String groupId, String artifactId, String version ) + { + StringBuilder sb = new StringBuilder(); + if ( groupId != null ) + { + sb.append( groupId ); + } + sb.append( ":" ); + if ( artifactId != null ) + { + sb.append( artifactId ); + } + sb.append( ":" ); + if ( version != null ) + { + sb.append( version ); + } + return sb.toString(); } @Override @@ -103,10 +146,8 @@ class DefaultModelCache { return false; } - - Key that = (Key) obj; - return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) - && version.equals( that.version ) && tag.equals( that.tag ); + GavCacheKey that = (GavCacheKey) obj; + return Objects.equals( this.gav, that.gav ) && Objects.equals( this.tag, that.tag ); } @Override @@ -115,5 +156,59 @@ class DefaultModelCache return hash; } + @Override + public String toString() + { + return "GavCacheKey{" + + "gav='" + gav + '\'' + + ", tag='" + tag + '\'' + + '}'; + } + } + + private static final class SourceCacheKey + { + private final Source source; + + private final String tag; + + private final int hash; + + SourceCacheKey( Source source, String tag ) + { + this.source = source; + this.tag = tag; + this.hash = Objects.hash( source, tag ); + } + + @Override + public String toString() + { + return "SourceCacheKey{" + + "source=" + source + + ", tag='" + tag + '\'' + + '}'; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( null == obj || !getClass().equals( obj.getClass() ) ) + { + return false; + } + SourceCacheKey that = (SourceCacheKey) obj; + return Objects.equals( this.source, that.source ) && Objects.equals( this.tag, that.tag ); + } + + @Override + public int hashCode() + { + return hash; + } } }