001    package org.apache.maven.artifact.repository;
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.io.File;
023    import java.util.Collections;
024    import java.util.List;
025    
026    import org.apache.maven.artifact.Artifact;
027    import org.apache.maven.artifact.metadata.ArtifactMetadata;
028    import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
029    import org.apache.maven.repository.Proxy;
030    
031    //TODO: completely separate local and remote artifact repositories
032    public class MavenArtifactRepository
033        implements ArtifactRepository
034    {
035        private String id;
036    
037        private String url;
038    
039        private String basedir;
040    
041        private String protocol;
042    
043        private ArtifactRepositoryLayout layout;
044    
045        private ArtifactRepositoryPolicy snapshots;
046    
047        private ArtifactRepositoryPolicy releases;
048    
049        private Authentication authentication;
050    
051        private Proxy proxy;
052    
053        private List<ArtifactRepository> mirroredRepositories = Collections.emptyList();
054    
055        public MavenArtifactRepository()
056        {
057        }
058    
059        /**
060         * Create a remote download repository.
061         *
062         * @param id        the unique identifier of the repository
063         * @param url       the URL of the repository
064         * @param layout    the layout of the repository
065         * @param snapshots the policies to use for snapshots
066         * @param releases  the policies to use for releases
067         */
068        public MavenArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
069                                        ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
070        {
071            this.id = id;
072            this.url = url;
073            this.layout = layout;
074            this.snapshots = snapshots;
075            this.releases = releases;
076            //
077            // Derive these from the URL
078            //
079            this.protocol = protocol( url );
080            this.basedir = basedir( url );
081        }
082    
083        public String pathOf( Artifact artifact )
084        {
085            return layout.pathOf( artifact );
086        }
087    
088        public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
089        {
090            return layout.pathOfRemoteRepositoryMetadata( artifactMetadata );
091        }
092    
093        public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
094        {
095            return layout.pathOfLocalRepositoryMetadata( metadata, repository );
096        }
097    
098        public void setLayout( ArtifactRepositoryLayout layout )
099        {
100            this.layout = layout;
101        }
102    
103        public ArtifactRepositoryLayout getLayout()
104        {
105            return layout;
106        }
107    
108        public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy snapshots )
109        {
110            this.snapshots = snapshots;
111        }
112    
113        public ArtifactRepositoryPolicy getSnapshots()
114        {
115            return snapshots;
116        }
117    
118        public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy releases )
119        {
120            this.releases = releases;
121        }
122    
123        public ArtifactRepositoryPolicy getReleases()
124        {
125            return releases;
126        }
127    
128        public String getKey()
129        {
130            return getId();
131        }
132    
133        public String toString()
134        {
135            StringBuilder sb = new StringBuilder();
136    
137            sb.append( "       id: " ).append( getId() ).append( "\n" );
138            sb.append( "      url: " ).append( getUrl() ).append( "\n" );
139            sb.append( "   layout: " ).append( layout != null ? layout : "none" ).append( "\n" );
140    
141            if ( snapshots != null )
142            {
143                sb.append( "snapshots: [enabled => " ).append( snapshots.isEnabled() );
144                sb.append( ", update => " ).append( snapshots.getUpdatePolicy() ).append( "]\n" );
145            }
146    
147            if ( releases != null )
148            {
149                sb.append( " releases: [enabled => " ).append( releases.isEnabled() );
150                sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( "]\n" );
151            }
152    
153            return sb.toString();
154        }
155    
156        public Artifact find( Artifact artifact )
157        {
158            File artifactFile = new File( getBasedir(), pathOf( artifact ) );
159    
160            // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
161            // with multiple local repository implementations yet.
162            artifact.setFile( artifactFile );
163    
164            return artifact;
165        }
166    
167        public List<String> findVersions( Artifact artifact )
168        {
169            return Collections.emptyList();
170        }
171    
172        public String getId()
173        {
174            return id;
175        }
176    
177        public String getUrl()
178        {
179            return url;
180        }
181    
182        public String getBasedir()
183        {
184            return basedir;
185        }
186    
187        public String getProtocol()
188        {
189            return protocol;
190        }
191    
192        public void setId( String id )
193        {
194            this.id = id;
195        }
196    
197        public void setUrl( String url )
198        {
199            this.url = url;
200    
201            this.protocol = protocol( url );
202            this.basedir = basedir( url );
203        }
204    
205        // Path Utils
206    
207        /**
208         * /**
209         * Return the protocol name.
210         * <br/>
211         * E.g: for input
212         * <code>http://www.codehause.org</code> this method will return <code>http</code>
213         *
214         * @param url the url
215         * @return the host name
216         */
217        private static String protocol( final String url )
218        {
219            final int pos = url.indexOf( ":" );
220    
221            if ( pos == -1 )
222            {
223                return "";
224            }
225            return url.substring( 0, pos ).trim();
226        }
227    
228        /**
229         * Derive the path portion of the given URL.
230         *
231         * @param url the repository URL
232         * @return the basedir of the repository
233         * @todo need to URL decode for spaces?
234         */
235        private String basedir( String url )
236        {
237            String retValue = null;
238    
239            if ( protocol.equalsIgnoreCase( "file" ) )
240            {
241                retValue = url.substring( protocol.length() + 1 );
242                retValue = decode( retValue );
243                // special case: if omitted // on protocol, keep path as is
244                if ( retValue.startsWith( "//" ) )
245                {
246                    retValue = retValue.substring( 2 );
247    
248                    if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
249                    {
250                        // special case: if there is a windows drive letter, then keep the original return value
251                        retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
252                    }
253                    else
254                    {
255                        // Now we expect the host
256                        int index = retValue.indexOf( "/" );
257                        if ( index >= 0 )
258                        {
259                            retValue = retValue.substring( index + 1 );
260                        }
261    
262                        // special case: if there is a windows drive letter, then keep the original return value
263                        if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
264                        {
265                            retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
266                        }
267                        else if ( index >= 0 )
268                        {
269                            // leading / was previously stripped
270                            retValue = "/" + retValue;
271                        }
272                    }
273                }
274    
275                // special case: if there is a windows drive letter using |, switch to :
276                if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
277                {
278                    retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
279                }
280    
281                // normalize separators
282                retValue = new File( retValue ).getPath();
283            }
284    
285            if ( retValue == null )
286            {
287                retValue = "/";
288            }
289            return retValue.trim();
290        }
291    
292        /**
293         * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
294         * convert URL-encoded octets to characters.
295         *
296         * @param url The URL to decode, may be <code>null</code>.
297         * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
298         */
299        private static String decode( String url )
300        {
301            String decoded = url;
302            if ( url != null )
303            {
304                int pos = -1;
305                while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
306                {
307                    if ( pos + 2 < decoded.length() )
308                    {
309                        String hexStr = decoded.substring( pos + 1, pos + 3 );
310                        char ch = (char) Integer.parseInt( hexStr, 16 );
311                        decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
312                    }
313                }
314            }
315            return decoded;
316        }
317    
318        public int hashCode()
319        {
320            final int prime = 31;
321            int result = 1;
322            result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
323            return result;
324        }
325    
326        public boolean equals( Object obj )
327        {
328            if ( this == obj )
329            {
330                return true;
331            }
332            if ( obj == null )
333            {
334                return false;
335            }
336            if ( getClass() != obj.getClass() )
337            {
338                return false;
339            }
340    
341            ArtifactRepository other = (ArtifactRepository) obj;
342    
343            return eq( getId(), other.getId() );
344        }
345    
346        protected static <T> boolean eq( T s1, T s2 )
347        {
348            return s1 != null ? s1.equals( s2 ) : s2 == null;
349        }
350    
351        public Authentication getAuthentication()
352        {
353            return authentication;
354        }
355    
356        public void setAuthentication( Authentication authentication )
357        {
358            this.authentication = authentication;
359        }
360    
361        public Proxy getProxy()
362        {
363            return proxy;
364        }
365    
366        public void setProxy( Proxy proxy )
367        {
368            this.proxy = proxy;
369        }
370    
371        public boolean isBlacklisted()
372        {
373            return false;
374        }
375    
376        public void setBlacklisted( boolean blackListed )
377        {
378            // no op
379        }
380    
381        public boolean isUniqueVersion()
382        {
383            return true;
384        }
385    
386        public boolean isProjectAware()
387        {
388            return false;
389        }
390    
391        public List<ArtifactRepository> getMirroredRepositories()
392        {
393            return mirroredRepositories;
394        }
395    
396        public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
397        {
398            if ( mirroredRepositories != null )
399            {
400                this.mirroredRepositories = mirroredRepositories;
401            }
402            else
403            {
404                this.mirroredRepositories = Collections.emptyList();
405            }
406        }
407    
408    }