001package org.apache.maven.scm.provider.bazaar.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
022import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
023import org.codehaus.plexus.util.StringUtils;
024
025import java.io.File;
026
027/**
028 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
029 *
030 */
031public class BazaarScmProviderRepository
032    extends ScmProviderRepositoryWithHost
033{
034    //Known and tested protocols
035    private static final String FILE = "file://";
036
037    private static final String SFTP = "sftp://";
038
039    private static final String FTP = "ftp://";
040
041    private static final String AFTP = "aftp://";
042
043    private static final String HTTP = "http://";
044
045    private static final String HTTPS = "https://";
046
047    private static final String BZR = "bzr://";
048
049    private static final String BZR_SSH = "bzr+ssh://";
050
051    /** this is basically an abbreviation of {@value #BZR_SSH} */
052    private static final String SSH = "ssh://";
053
054    private static final String UNKNOWN = "";
055
056    private final String path;
057
058    private final String protocol;
059
060    private final String orgUrl;
061
062    public BazaarScmProviderRepository( String url )
063    {
064        orgUrl = url;
065        protocol = getProtocol( url );
066        path = parseUrl( url );
067    }
068
069    public String getURI()
070    {
071        if ( FILE.equals( protocol ) )
072        {
073            return orgUrl;
074        }
075        else
076        {
077            return protocol + ( needsAuthentication() ? addUser() + addPassword() + addAt() : "" ) + addHost()
078                + addPort() + addPath();
079        }
080    }
081
082    /**
083     * @return A message if the repository as an invalid URI, null if the URI seems fine.
084     */
085    public String validateURI()
086    {
087
088        String msg = null;
089
090        if ( UNKNOWN.equals( protocol ) )
091        {
092            msg = "Unknown protocol (URL should start with something like 'sftp://' or 'file://'";
093        }
094        else if ( needsAuthentication() )
095        {
096            if ( getUser() == null )
097            {
098                msg = "Username is missing for protocol " + protocol;
099            }
100            else if ( getPassword() == null )
101            {
102                msg = "Password is missing for protocol " + protocol;
103            }
104            else if ( getHost() == null )
105            {
106                msg = "Host (eg. www.myhost.com) is missing for protocol " + protocol;
107            }
108        }
109
110        else if ( getPort() != 0 && getHost() == null )
111        {
112            msg = "Got port information without any host for protocol " + protocol;
113        }
114
115        if ( msg != null )
116        {
117            msg = "Something could be wrong about the repository URL: " + orgUrl + "\nReason: " + msg
118                + "\nCheck http://maven.apache.org/scm for usage and hints.";
119        }
120        return msg;
121    }
122
123    private String getProtocol( String url )
124    {
125        String prot = UNKNOWN;
126        if ( url.startsWith( FILE ) )
127        {
128            prot = FILE;
129        }
130        else if ( url.startsWith( FTP ) )
131        {
132            prot = FTP;
133        }
134        else if ( url.startsWith( SFTP ) )
135        {
136            prot = SFTP;
137        }
138        else if ( url.startsWith( AFTP ) )
139        {
140            prot = AFTP;
141        }
142        else if ( url.startsWith( HTTP ) )
143        {
144            prot = HTTP;
145        }
146        else if ( url.startsWith( HTTPS ) )
147        {
148            prot = HTTPS;
149        }
150        else if ( url.startsWith( BZR ) )
151        {
152            prot = BZR;
153        }
154        else if ( url.startsWith( BZR_SSH ) )
155        {
156            prot = BZR_SSH;
157        }
158        else if ( url.startsWith( SSH ) )
159        {
160            prot = SSH;
161        }
162
163        return prot;
164    }
165
166    private String parseUrl( String url )
167    {
168        if ( UNKNOWN.equals( protocol ) )
169        {
170            return url;
171        }
172
173        //Strip protocol
174        url = url.substring( protocol.length() );
175
176        url = parseUsernameAndPassword( url );
177
178        url = parseHostAndPort( url );
179
180        url = parsePath( url );
181
182        return url; //is now only the path
183    }
184
185    private String parseHostAndPort( String url )
186    {
187        if ( !FILE.equals( protocol ) )
188        {
189            int indexSlash = url.indexOf( '/' );
190
191            String hostPort = url;
192            if ( indexSlash > 0 )
193            {
194                hostPort = url.substring( 0, indexSlash );
195            }
196
197            int indexColon = hostPort.indexOf( ':' );
198            if ( indexColon > 0 )
199            {
200                setHost( hostPort.substring( 0, indexColon ) );
201                url = StringUtils.replace( url, getHost(), "" );
202                setPort( Integer.parseInt( hostPort.substring( indexColon + 1 ) ) );
203                url = StringUtils.replace( url, ":" + getPort(), "" );
204            }
205            else
206            {
207                setHost( hostPort );
208                url = StringUtils.replace( url, getHost(), "" );
209            }
210        }
211
212        return url;
213    }
214
215    private String parseUsernameAndPassword( String url )
216    {
217        if ( needsAuthentication() )
218        {
219            String[] split = url.split( "@" );
220            if ( split.length == 2 )
221            {
222                url = split[1]; //Strip away 'username:password@' from url
223                split = split[0].split( ":" );
224                if ( split.length == 2 )
225                { //both username and password
226                    setUser( split[0] );
227                    setPassword( split[1] );
228                }
229                else
230                { //only username
231                    setUser( split[0] );
232                }
233            }
234        }
235        return url;
236    }
237
238    private String parsePath( String url )
239    {
240        if ( FILE.equals( protocol ) )
241        {
242            //Use OS dependent path separator
243            url = StringUtils.replace( url, "/", File.separator );
244
245            //Test first path separator (*nix systems use them to denote root)
246            File tmpFile = new File( url ); //most likly a *nix system
247            String url2 = url.substring( File.pathSeparator.length() );
248            File tmpFile2 = new File( url2 ); //most likly a windows system
249            if ( !tmpFile.exists() && !tmpFile2.exists() )
250            {
251                // This is trouble - Trouble is reported in validateURI()
252            }
253
254            url = tmpFile2.exists() ? url2 : url;
255
256            //Use URL path separator
257            url = StringUtils.replace( url, File.separator, "/" );
258        }
259
260        return url;
261    }
262
263    private String addUser()
264    {
265        return ( getUser() == null ) ? "" : getUser();
266    }
267
268    private String addPassword()
269    {
270        return ( getPassword() == null ) ? "" : ":" + getPassword();
271    }
272
273    private String addAt()
274    {
275        return needsAuthentication() ? "@" : "";
276    }
277
278    private String addHost()
279    {
280        return ( getHost() == null ) ? "" : getHost();
281    }
282
283    private String addPort()
284    {
285        return ( getPort() == 0 ) ? "" : ":" + getPort();
286    }
287
288    private String addPath()
289    {
290        return path;
291    }
292
293    private boolean needsAuthentication()
294    {
295        return SFTP.equals( protocol ) || 
296               FTP.equals( protocol ) || 
297               HTTPS.equals( protocol ) || 
298               AFTP.equals( protocol ) ||
299               BZR.equals( protocol ) ||
300               BZR_SSH.equals( protocol ) ||
301               SSH.equals( protocol );
302    }
303
304    /** {@inheritDoc} */
305    public String toString()
306    {
307        return "Bazaar Repository Interpreted from: " + orgUrl + ":\nProtocol: " + protocol + "\nHost: "
308            + getHost() + "\nPort: " + getPort() + "\nUsername: " + getUser() + "\nPassword: " + getPassword()
309            + "\nPath: " + path;
310    }
311}