001    package 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    
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.concurrent.ConcurrentHashMap;
027    
028    import org.apache.maven.artifact.Artifact;
029    import org.apache.maven.model.Plugin;
030    import org.apache.maven.project.MavenProject;
031    import org.codehaus.plexus.classworlds.realm.ClassRealm;
032    import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
033    import org.codehaus.plexus.component.annotations.Component;
034    import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
035    import org.eclipse.aether.RepositorySystemSession;
036    import org.eclipse.aether.graph.DependencyFilter;
037    import org.eclipse.aether.repository.LocalRepository;
038    import org.eclipse.aether.repository.RemoteRepository;
039    import org.eclipse.aether.repository.WorkspaceRepository;
040    
041    /**
042     * Default PluginCache implementation. Assumes cached data does not change.
043     */
044    @Component( role = PluginRealmCache.class )
045    public class DefaultPluginRealmCache
046        implements PluginRealmCache, Disposable
047    {
048    
049        protected static class CacheKey
050            implements Key
051        {
052    
053            private final Plugin plugin;
054    
055            private final WorkspaceRepository workspace;
056    
057            private final LocalRepository localRepo;
058    
059            private final List<RemoteRepository> repositories;
060    
061            private final ClassLoader parentRealm;
062    
063            private final Map<String, ClassLoader> foreignImports;
064    
065            private final DependencyFilter filter;
066    
067            private final int hashCode;
068    
069            public CacheKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
070                             DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
071                             RepositorySystemSession session )
072            {
073                this.plugin = plugin.clone();
074                this.workspace = CacheUtils.getWorkspace( session );
075                this.localRepo = session.getLocalRepository();
076                this.repositories = new ArrayList<RemoteRepository>( repositories.size() );
077                for ( RemoteRepository repository : repositories )
078                {
079                    if ( repository.isRepositoryManager() )
080                    {
081                        this.repositories.addAll( repository.getMirroredRepositories() );
082                    }
083                    else
084                    {
085                        this.repositories.add( repository );
086                    }
087                }
088                this.parentRealm = parentRealm;
089                this.foreignImports =
090                    ( foreignImports != null ) ? foreignImports : Collections.<String, ClassLoader> emptyMap();
091                this.filter = dependencyFilter;
092    
093                int hash = 17;
094                hash = hash * 31 + CacheUtils.pluginHashCode( plugin );
095                hash = hash * 31 + hash( workspace );
096                hash = hash * 31 + hash( localRepo );
097                hash = hash * 31 + CacheUtils.repositoriesHashCode( repositories );
098                hash = hash * 31 + hash( parentRealm );
099                hash = hash * 31 + this.foreignImports.hashCode();
100                hash = hash * 31 + hash( dependencyFilter );
101                this.hashCode = hash;
102            }
103    
104            @Override
105            public String toString()
106            {
107                return plugin.getId();
108            }
109    
110            @Override
111            public int hashCode()
112            {
113                return hashCode;
114            }
115    
116            private static int hash( Object obj )
117            {
118                return obj != null ? obj.hashCode() : 0;
119            }
120    
121            @Override
122            public boolean equals( Object o )
123            {
124                if ( o == this )
125                {
126                    return true;
127                }
128    
129                if ( !( o instanceof CacheKey ) )
130                {
131                    return false;
132                }
133    
134                CacheKey that = (CacheKey) o;
135    
136                return parentRealm == that.parentRealm && CacheUtils.pluginEquals( plugin, that.plugin )
137                    && eq( workspace, that.workspace ) && eq( localRepo, that.localRepo )
138                    && CacheUtils.repositoriesEquals( this.repositories, that.repositories ) && eq( filter, that.filter )
139                    && eq( foreignImports, that.foreignImports );
140            }
141    
142            private static <T> boolean eq( T s1, T s2 )
143            {
144                return s1 != null ? s1.equals( s2 ) : s2 == null;
145            }
146    
147        }
148    
149        protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<Key, CacheRecord>();
150    
151        public Key createKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
152                              DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
153                              RepositorySystemSession session )
154        {
155            return new CacheKey( plugin, parentRealm, foreignImports, dependencyFilter, repositories, session );
156        }
157    
158        public CacheRecord get( Key key )
159        {
160            return cache.get( key );
161        }
162    
163        public CacheRecord put( Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts )
164        {
165            if ( pluginRealm == null || pluginArtifacts == null )
166            {
167                throw new IllegalArgumentException();
168            }
169    
170            if ( cache.containsKey( key ) )
171            {
172                throw new IllegalStateException( "Duplicate plugin realm for plugin " + key );
173            }
174    
175            CacheRecord record = new CacheRecord( pluginRealm, pluginArtifacts );
176    
177            cache.put( key, record );
178    
179            return record;
180        }
181    
182        public void flush()
183        {
184            for ( CacheRecord record : cache.values() )
185            {
186                ClassRealm realm = record.realm;
187                try
188                {
189                    realm.getWorld().disposeRealm( realm.getId() );
190                }
191                catch ( NoSuchRealmException e )
192                {
193                    // ignore
194                }
195            }
196            cache.clear();
197        }
198    
199        protected static int pluginHashCode( Plugin plugin )
200        {
201            return CacheUtils.pluginHashCode( plugin );
202        }
203    
204        protected static boolean pluginEquals( Plugin a, Plugin b )
205        {
206            return CacheUtils.pluginEquals( a, b );
207        }
208    
209        public void register( MavenProject project, CacheRecord record )
210        {
211            // default cache does not track plugin usage
212        }
213    
214        public void dispose()
215        {
216            flush();
217        }
218    
219    }