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 }