001package org.apache.maven.plugin;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.apache.commons.lang3.Validate;
029import org.apache.maven.artifact.Artifact;
030import org.apache.maven.model.Plugin;
031import org.apache.maven.project.MavenProject;
032import org.codehaus.plexus.component.annotations.Component;
033import org.eclipse.aether.RepositorySystemSession;
034import org.eclipse.aether.graph.DependencyFilter;
035import org.eclipse.aether.repository.LocalRepository;
036import org.eclipse.aether.repository.RemoteRepository;
037import org.eclipse.aether.repository.WorkspaceRepository;
038
039/**
040 * @author Igor Fedorenko
041 * @author Benjamin Bentmann
042 */
043@Component( role = PluginArtifactsCache.class )
044public class DefaultPluginArtifactsCache
045    implements PluginArtifactsCache
046{
047
048    protected static class CacheKey
049        implements Key
050    {
051
052        private final Plugin plugin;
053
054        private final WorkspaceRepository workspace;
055
056        private final LocalRepository localRepo;
057
058        private final List<RemoteRepository> repositories;
059
060        private final DependencyFilter filter;
061
062        private final int hashCode;
063
064        public CacheKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
065                         RepositorySystemSession session )
066        {
067            this.plugin = plugin.clone();
068            workspace = CacheUtils.getWorkspace( session );
069            this.localRepo = session.getLocalRepository();
070            this.repositories = new ArrayList<>( repositories.size() );
071            for ( RemoteRepository repository : repositories )
072            {
073                if ( repository.isRepositoryManager() )
074                {
075                    this.repositories.addAll( repository.getMirroredRepositories() );
076                }
077                else
078                {
079                    this.repositories.add( repository );
080                }
081            }
082            this.filter = extensionFilter;
083
084            int hash = 17;
085            hash = hash * 31 + CacheUtils.pluginHashCode( plugin );
086            hash = hash * 31 + hash( workspace );
087            hash = hash * 31 + hash( localRepo );
088            hash = hash * 31 + CacheUtils.repositoriesHashCode( repositories );
089            hash = hash * 31 + hash( extensionFilter );
090            this.hashCode = hash;
091        }
092
093        @Override
094        public String toString()
095        {
096            return plugin.getId();
097        }
098
099        @Override
100        public int hashCode()
101        {
102            return hashCode;
103        }
104
105        private static int hash( Object obj )
106        {
107            return obj != null ? obj.hashCode() : 0;
108        }
109
110        @Override
111        public boolean equals( Object o )
112        {
113            if ( o == this )
114            {
115                return true;
116            }
117
118            if ( !( o instanceof CacheKey ) )
119            {
120                return false;
121            }
122
123            CacheKey that = (CacheKey) o;
124
125            return CacheUtils.pluginEquals( plugin, that.plugin ) && eq( workspace, that.workspace )
126                && eq( localRepo, that.localRepo ) && CacheUtils.repositoriesEquals( repositories, that.repositories )
127                && eq( filter, that.filter );
128        }
129
130        private static <T> boolean eq( T s1, T s2 )
131        {
132            return s1 != null ? s1.equals( s2 ) : s2 == null;
133        }
134
135    }
136
137    protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
138
139    public Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
140                          RepositorySystemSession session )
141    {
142        return new CacheKey( plugin, extensionFilter, repositories, session );
143    }
144
145    public CacheRecord get( Key key )
146        throws PluginResolutionException
147    {
148        CacheRecord cacheRecord = cache.get( key );
149
150        if ( cacheRecord != null && cacheRecord.exception != null )
151        {
152            throw cacheRecord.exception;
153        }
154
155        return cacheRecord;
156    }
157
158    public CacheRecord put( Key key, List<Artifact> pluginArtifacts )
159    {
160        Validate.notNull( pluginArtifacts, "pluginArtifacts cannot be null" );
161
162        assertUniqueKey( key );
163
164        CacheRecord record =
165            new CacheRecord( Collections.unmodifiableList( new ArrayList<>( pluginArtifacts ) ) );
166
167        cache.put( key, record );
168
169        return record;
170    }
171
172    protected void assertUniqueKey( Key key )
173    {
174        if ( cache.containsKey( key ) )
175        {
176            throw new IllegalStateException( "Duplicate artifact resolution result for plugin " + key );
177        }
178    }
179
180    public CacheRecord put( Key key, PluginResolutionException exception )
181    {
182        Validate.notNull( exception, "exception cannot be null" );
183
184        assertUniqueKey( key );
185
186        CacheRecord record = new CacheRecord( exception );
187
188        cache.put( key, record );
189
190        return record;
191    }
192
193    public void flush()
194    {
195        cache.clear();
196    }
197
198    protected static int pluginHashCode( Plugin plugin )
199    {
200        return CacheUtils.pluginHashCode( plugin );
201    }
202
203    protected static boolean pluginEquals( Plugin a, Plugin b )
204    {
205        return CacheUtils.pluginEquals( a, b );
206    }
207
208    public void register( MavenProject project, Key cacheKey, CacheRecord record )
209    {
210        // default cache does not track record usage
211    }
212
213}