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.io.File;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.apache.maven.artifact.Artifact;
029import org.apache.maven.project.ExtensionDescriptor;
030import org.apache.maven.project.MavenProject;
031import org.codehaus.plexus.classworlds.realm.ClassRealm;
032import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
033import org.codehaus.plexus.component.annotations.Component;
034import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
035
036/**
037 * Default extension realm cache implementation. Assumes cached data does not change.
038 */
039@Component( role = ExtensionRealmCache.class )
040public class DefaultExtensionRealmCache
041    implements ExtensionRealmCache, Disposable
042{
043
044    protected static class CacheKey
045        implements Key
046    {
047
048        private final List<File> files;
049
050        private final List<Long> timestamps;
051
052        private final List<Long> sizes;
053
054        private final List<String> ids;
055
056        private final int hashCode;
057
058        public CacheKey( List<Artifact> extensionArtifacts )
059        {
060            this.files = new ArrayList<File>( extensionArtifacts.size() );
061            this.timestamps = new ArrayList<Long>( extensionArtifacts.size() );
062            this.sizes = new ArrayList<Long>( extensionArtifacts.size() );
063            this.ids = new ArrayList<String>( extensionArtifacts.size() );
064
065            for ( Artifact artifact : extensionArtifacts )
066            {
067                File file = artifact.getFile();
068                files.add( file );
069                timestamps.add( ( file != null ) ? Long.valueOf( file.lastModified() ) : Long.valueOf( 0 ) );
070                sizes.add( ( file != null ) ? Long.valueOf( file.length() ) : Long.valueOf( 0 ) );
071                ids.add( artifact.getVersion() );
072            }
073
074            this.hashCode =
075                31 * files.hashCode() + 31 * ids.hashCode() + 31 * timestamps.hashCode() + 31 * sizes.hashCode();
076        }
077
078        @Override
079        public int hashCode()
080        {
081            return hashCode;
082        }
083
084        @Override
085        public boolean equals( Object o )
086        {
087            if ( o == this )
088            {
089                return true;
090            }
091
092            if ( !( o instanceof CacheKey ) )
093            {
094                return false;
095            }
096
097            CacheKey other = (CacheKey) o;
098
099            return ids.equals( other.ids ) && files.equals( other.files ) && timestamps.equals( other.timestamps )
100                && sizes.equals( other.sizes );
101        }
102
103        @Override
104        public String toString()
105        {
106            return files.toString();
107        }
108    }
109
110    protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<Key, CacheRecord>();
111
112    @Override
113    public Key createKey( List<Artifact> extensionArtifacts )
114    {
115        return new CacheKey( extensionArtifacts );
116    }
117
118    public CacheRecord get( Key key )
119    {
120        return cache.get( key );
121    }
122
123    public CacheRecord put( Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor,
124                            List<Artifact> artifacts )
125    {
126        if ( extensionRealm == null )
127        {
128            throw new NullPointerException();
129        }
130
131        if ( cache.containsKey( key ) )
132        {
133            throw new IllegalStateException( "Duplicate extension realm for extension " + key );
134        }
135
136        CacheRecord record = new CacheRecord( extensionRealm, extensionDescriptor, artifacts );
137
138        cache.put( key, record );
139
140        return record;
141    }
142
143    public void flush()
144    {
145        for ( CacheRecord record : cache.values() )
146        {
147            ClassRealm realm = record.realm;
148            try
149            {
150                realm.getWorld().disposeRealm( realm.getId() );
151            }
152            catch ( NoSuchRealmException e )
153            {
154                // ignore
155            }
156        }
157        cache.clear();
158    }
159
160    public void register( MavenProject project, Key key, CacheRecord record )
161    {
162        // default cache does not track extension usage
163    }
164
165    public void dispose()
166    {
167        flush();
168    }
169
170}