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