001package org.apache.maven.artifact.repository.metadata;
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.io.IOException;
024import java.io.Reader;
025import java.io.Writer;
026
027import org.apache.maven.artifact.Artifact;
028import org.apache.maven.artifact.metadata.ArtifactMetadata;
029import org.apache.maven.artifact.repository.ArtifactRepository;
030import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
031import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
032import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
033import org.codehaus.plexus.util.IOUtil;
034import org.codehaus.plexus.util.ReaderFactory;
035import org.codehaus.plexus.util.WriterFactory;
036import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
037
038/**
039 * Shared methods of the repository metadata handling.
040 *
041 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
042 */
043public abstract class AbstractRepositoryMetadata
044    implements RepositoryMetadata
045{
046    private Metadata metadata;
047
048    protected AbstractRepositoryMetadata( Metadata metadata )
049    {
050        this.metadata = metadata;
051    }
052
053    public String getRemoteFilename()
054    {
055        return "maven-metadata.xml";
056    }
057
058    public String getLocalFilename( ArtifactRepository repository )
059    {
060        return "maven-metadata-" + repository.getKey() + ".xml";
061    }
062
063    public void storeInLocalRepository( ArtifactRepository localRepository,
064                                        ArtifactRepository remoteRepository )
065        throws RepositoryMetadataStoreException
066    {
067        try
068        {
069            updateRepositoryMetadata( localRepository, remoteRepository );
070        }
071        catch ( IOException e )
072        {
073            throw new RepositoryMetadataStoreException( "Error updating group repository metadata", e );
074        }
075        catch ( XmlPullParserException e )
076        {
077            throw new RepositoryMetadataStoreException( "Error updating group repository metadata", e );
078        }
079    }
080
081    protected void updateRepositoryMetadata( ArtifactRepository localRepository,
082                                             ArtifactRepository remoteRepository )
083        throws IOException, XmlPullParserException
084    {
085        MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
086
087        Metadata metadata = null;
088
089        File metadataFile = new File( localRepository.getBasedir(),
090            localRepository.pathOfLocalRepositoryMetadata( this, remoteRepository ) );
091
092        if ( metadataFile.length() == 0 )
093        {
094            if ( !metadataFile.delete() )
095            {
096                // sleep for 10ms just in case this is windows holding a file lock
097                try
098                {
099                    Thread.sleep( 10 );
100                }
101                catch ( InterruptedException e )
102                {
103                    // ignore
104                }
105                metadataFile.delete(); // if this fails, forget about it, we'll try to overwrite it anyway so no need
106                                       // to delete on exit
107            }
108        }
109        else if ( metadataFile.exists() )
110        {
111            Reader reader = null;
112
113            try
114            {
115                reader = ReaderFactory.newXmlReader( metadataFile );
116
117                metadata = mappingReader.read( reader, false );
118            }
119            finally
120            {
121                IOUtil.close( reader );
122            }
123        }
124
125        boolean changed;
126
127        // If file could not be found or was not valid, start from scratch
128        if ( metadata == null )
129        {
130            metadata = this.metadata;
131
132            changed = true;
133        }
134        else
135        {
136            changed = metadata.merge( this.metadata );
137        }
138
139        // beware meta-versions!
140        String version = metadata.getVersion();
141        if ( version != null && ( Artifact.LATEST_VERSION.equals( version ) || Artifact.RELEASE_VERSION.equals(
142            version ) ) )
143        {
144            // meta-versions are not valid <version/> values...don't write them.
145            metadata.setVersion( null );
146        }
147
148        if ( changed || !metadataFile.exists() )
149        {
150            Writer writer = null;
151            try
152            {
153                metadataFile.getParentFile().mkdirs();
154                writer = WriterFactory.newXmlWriter( metadataFile );
155
156                MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer();
157
158                mappingWriter.write( writer, metadata );
159            }
160            finally
161            {
162                IOUtil.close( writer );
163            }
164        }
165        else
166        {
167            metadataFile.setLastModified( System.currentTimeMillis() );
168        }
169    }
170
171    public String toString()
172    {
173        return "repository metadata for: \'" + getKey() + "\'";
174    }
175
176    protected static Metadata createMetadata( Artifact artifact,
177                                              Versioning versioning )
178    {
179        Metadata metadata = new Metadata();
180        metadata.setGroupId( artifact.getGroupId() );
181        metadata.setArtifactId( artifact.getArtifactId() );
182        metadata.setVersion( artifact.getVersion() );
183        metadata.setVersioning( versioning );
184        return metadata;
185    }
186
187    protected static Versioning createVersioning( Snapshot snapshot )
188    {
189        Versioning versioning = new Versioning();
190        versioning.setSnapshot( snapshot );
191        versioning.updateTimestamp();
192        return versioning;
193    }
194
195    public void setMetadata( Metadata metadata )
196    {
197        this.metadata = metadata;
198    }
199
200    public Metadata getMetadata()
201    {
202        return metadata;
203    }
204
205    public void merge( org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata )
206    {
207        // TODO: not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact replaces?
208        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
209        this.metadata.merge( repoMetadata.getMetadata() );
210    }
211
212    public void merge( ArtifactMetadata metadata )
213    {
214        // TODO: not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact replaces?
215        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
216        this.metadata.merge( repoMetadata.getMetadata() );
217    }
218
219    public String extendedToString()
220    {
221        StringBuilder buffer = new StringBuilder();
222
223        buffer.append( "\nRepository Metadata\n--------------------------" );
224        buffer.append( "\nGroupId: " ).append( getGroupId() );
225        buffer.append( "\nArtifactId: " ).append( getArtifactId() );
226        buffer.append( "\nMetadata Type: " ).append( getClass().getName() );
227
228        return buffer.toString();
229    }
230
231    public int getNature()
232    {
233        return RELEASE;
234    }
235
236    public ArtifactRepositoryPolicy getPolicy( ArtifactRepository repository )
237    {
238        int nature = getNature();
239        if ( ( nature & RepositoryMetadata.RELEASE_OR_SNAPSHOT ) == RepositoryMetadata.RELEASE_OR_SNAPSHOT )
240        {
241            ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy( repository.getReleases() );
242            policy.merge( repository.getSnapshots() );
243            return policy;
244        }
245        else if ( ( nature & RepositoryMetadata.SNAPSHOT ) != 0 )
246        {
247            return repository.getSnapshots();
248        }
249        else
250        {
251            return repository.getReleases();
252        }
253    }
254
255}