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.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.maven.artifact.ArtifactUtils;
028import org.apache.maven.model.Plugin;
029import org.apache.maven.plugin.descriptor.MojoDescriptor;
030import org.apache.maven.plugin.descriptor.PluginDescriptor;
031import org.codehaus.plexus.component.annotations.Component;
032import org.codehaus.plexus.component.repository.ComponentDescriptor;
033import org.eclipse.aether.RepositorySystemSession;
034import org.eclipse.aether.repository.LocalRepository;
035import org.eclipse.aether.repository.RemoteRepository;
036import org.eclipse.aether.repository.WorkspaceRepository;
037
038/**
039 * Caches raw plugin descriptors. A raw plugin descriptor is a descriptor that has just been extracted from the plugin
040 * artifact and does not contain any runtime specific data. The cache must not be used for descriptors that hold runtime
041 * data like the plugin realm. <strong>Warning:</strong> This is an internal utility interface that is only public for
042 * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
043 * prior notice.
044 * 
045 * @since 3.0
046 * @author Benjamin Bentmann
047 */
048@Component( role = PluginDescriptorCache.class )
049public class DefaultPluginDescriptorCache
050    implements PluginDescriptorCache
051{
052
053    private Map<Key, PluginDescriptor> descriptors = new HashMap<Key, PluginDescriptor>( 128 );
054
055    public void flush()
056    {
057        descriptors.clear();
058    }
059
060    public Key createKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
061    {
062        return new CacheKey( plugin, repositories, session );
063    }
064
065    public PluginDescriptor get( Key cacheKey )
066    {
067        return clone( descriptors.get( cacheKey ) );
068    }
069
070    public void put( Key cacheKey, PluginDescriptor pluginDescriptor )
071    {
072        descriptors.put( cacheKey, clone( pluginDescriptor ) );
073    }
074
075    protected static PluginDescriptor clone( PluginDescriptor original )
076    {
077        PluginDescriptor clone = null;
078
079        if ( original != null )
080        {
081            clone = new PluginDescriptor();
082
083            clone.setGroupId( original.getGroupId() );
084            clone.setArtifactId( original.getArtifactId() );
085            clone.setVersion( original.getVersion() );
086            clone.setGoalPrefix( original.getGoalPrefix() );
087            clone.setInheritedByDefault( original.isInheritedByDefault() );
088
089            clone.setName( original.getName() );
090            clone.setDescription( original.getDescription() );
091            clone.setRequiredMavenVersion( original.getRequiredMavenVersion() );
092
093            clone.setPluginArtifact( ArtifactUtils.copyArtifactSafe( original.getPluginArtifact() ) );
094
095            clone.setComponents( clone( original.getMojos(), clone ) );
096            clone.setId( original.getId() );
097            clone.setIsolatedRealm( original.isIsolatedRealm() );
098            clone.setSource( original.getSource() );
099
100            clone.setDependencies( original.getDependencies() );
101        }
102
103        return clone;
104    }
105
106    private static List<ComponentDescriptor<?>> clone( List<MojoDescriptor> mojos, PluginDescriptor pluginDescriptor )
107    {
108        List<ComponentDescriptor<?>> clones = null;
109
110        if ( mojos != null )
111        {
112            clones = new ArrayList<ComponentDescriptor<?>>( mojos.size() );
113
114            for ( MojoDescriptor mojo : mojos )
115            {
116                MojoDescriptor clone = mojo.clone();
117                clone.setPluginDescriptor( pluginDescriptor );
118                clones.add( clone );
119            }
120        }
121
122        return clones;
123    }
124
125    private static final class CacheKey
126        implements Key
127    {
128
129        private final String groupId;
130
131        private final String artifactId;
132
133        private final String version;
134
135        private final WorkspaceRepository workspace;
136
137        private final LocalRepository localRepo;
138
139        private final List<RemoteRepository> repositories;
140
141        private final int hashCode;
142
143        public CacheKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
144        {
145            groupId = plugin.getGroupId();
146            artifactId = plugin.getArtifactId();
147            version = plugin.getVersion();
148
149            workspace = CacheUtils.getWorkspace( session );
150            localRepo = session.getLocalRepository();
151            this.repositories = new ArrayList<RemoteRepository>( repositories.size() );
152            for ( RemoteRepository repository : repositories )
153            {
154                if ( repository.isRepositoryManager() )
155                {
156                    this.repositories.addAll( repository.getMirroredRepositories() );
157                }
158                else
159                {
160                    this.repositories.add( repository );
161                }
162            }
163
164            int hash = 17;
165            hash = hash * 31 + groupId.hashCode();
166            hash = hash * 31 + artifactId.hashCode();
167            hash = hash * 31 + version.hashCode();
168            hash = hash * 31 + hash( workspace );
169            hash = hash * 31 + localRepo.hashCode();
170            hash = hash * 31 + CacheUtils.repositoriesHashCode( repositories );
171            this.hashCode = hash;
172        }
173
174        @Override
175        public int hashCode()
176        {
177            return hashCode;
178        }
179
180        @Override
181        public boolean equals( Object obj )
182        {
183            if ( this == obj )
184            {
185                return true;
186            }
187
188            if ( !( obj instanceof CacheKey ) )
189            {
190                return false;
191            }
192
193            CacheKey that = (CacheKey) obj;
194
195            return eq( this.artifactId, that.artifactId ) && eq( this.groupId, that.groupId )
196                && eq( this.version, that.version ) && eq( this.localRepo, that.localRepo )
197                && eq( this.workspace, that.workspace )
198                && CacheUtils.repositoriesEquals( this.repositories, that.repositories );
199        }
200
201        @Override
202        public String toString()
203        {
204            return groupId + ':' + artifactId + ':' + version;
205        }
206
207        private static int hash( Object obj )
208        {
209            return obj != null ? obj.hashCode() : 0;
210        }
211
212        private static <T> boolean eq( T s1, T s2 )
213        {
214            return s1 != null ? s1.equals( s2 ) : s2 == null;
215        }
216
217    }
218
219}