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         * Return the protocol name.
209         * <br/>
210         * E.g: for input
211         * <code>http://www.codehause.org</code> this method will return <code>http</code>
212         *
213         * @param url the url
214         * @return the host name
215         */
216        private static String protocol( final String url )
217        {
218            final int pos = url.indexOf( ":" );
219    
220            if ( pos == -1 )
221            {
222                return "";
223            }
224            return url.substring( 0, pos ).trim();
225        }
226    
227        /**
228         * Derive the path portion of the given URL.
229         *
230         * @param url the repository URL
231         * @return the basedir of the repository
232         * @todo need to URL decode for spaces?
233         */
234        private String basedir( String url )
235        {
236            String retValue = null;
237    
238            if ( protocol.equalsIgnoreCase( "file" ) )
239            {
240                retValue = url.substring( protocol.length() + 1 );
241                retValue = decode( retValue );
242                // special case: if omitted // on protocol, keep path as is
243                if ( retValue.startsWith( "//" ) )
244                {
245                    retValue = retValue.substring( 2 );
246    
247                    if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
248                    {
249                        // special case: if there is a windows drive letter, then keep the original return value
250                        retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
251                    }
252                    else
253                    {
254                        // Now we expect the host
255                        int index = retValue.indexOf( "/" );
256                        if ( index >= 0 )
257                        {
258                            retValue = retValue.substring( index + 1 );
259                        }
260    
261                        // special case: if there is a windows drive letter, then keep the original return value
262                        if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
263                        {
264                            retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
265                        }
266                        else if ( index >= 0 )
267                        {
268                            // leading / was previously stripped
269                            retValue = "/" + retValue;
270                        }
271                    }
272                }
273    
274                // special case: if there is a windows drive letter using |, switch to :
275                if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
276                {
277                    retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
278                }
279    
280                // normalize separators
281                retValue = new File( retValue ).getPath();
282            }
283    
284            if ( retValue == null )
285            {
286                retValue = "/";
287            }
288            return retValue.trim();
289        }
290    
291        /**
292         * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
293         * convert URL-encoded bytes to characters.
294         *
295         * @param url The URL to decode, may be <code>null</code>.
296         * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
297         */
298        private static String decode( String url )
299        {
300            String decoded = url;
301            if ( url != null )
302            {
303                int pos = -1;
304                while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
305                {
306                    if ( pos + 2 < decoded.length() )
307                    {
308                        String hexStr = decoded.substring( pos + 1, pos + 3 );
309                        char ch = (char) Integer.parseInt( hexStr, 16 );
310                        decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
311                    }
312                }
313            }
314            return decoded;
315        }
316    
317        public int hashCode()
318        {
319            final int prime = 31;
320            int result = 1;
321            result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
322            return result;
323        }
324    
325        public boolean equals( Object obj )
326        {
327            if ( this == obj )
328            {
329                return true;
330            }
331            if ( obj == null )
332            {
333                return false;
334            }
335            if ( getClass() != obj.getClass() )
336            {
337                return false;
338            }
339    
340            ArtifactRepository other = (ArtifactRepository) obj;
341    
342            return eq( getId(), other.getId() );
343        }
344    
345        protected static <T> boolean eq( T s1, T s2 )
346        {
347            return s1 != null ? s1.equals( s2 ) : s2 == null;
348        }
349    
350        public Authentication getAuthentication()
351        {
352            return authentication;
353        }
354    
355        public void setAuthentication( Authentication authentication )
356        {
357            this.authentication = authentication;
358        }
359    
360        public Proxy getProxy()
361        {
362            return proxy;
363        }
364    
365        public void setProxy( Proxy proxy )
366        {
367            this.proxy = proxy;
368        }
369    
370        public boolean isBlacklisted()
371        {
372            return false;
373        }
374    
375        public void setBlacklisted( boolean blackListed )
376        {
377            // no op
378        }
379    
380        public boolean isUniqueVersion()
381        {
382            return true;
383        }
384    
385        public boolean isProjectAware()
386        {
387            return false;
388        }
389    
390        public List<ArtifactRepository> getMirroredRepositories()
391        {
392            return mirroredRepositories;
393        }
394    
395        public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
396        {
397            if ( mirroredRepositories != null )
398            {
399                this.mirroredRepositories = mirroredRepositories;
400            }
401            else
402            {
403                this.mirroredRepositories = Collections.emptyList();
404            }
405        }
406    
407    }