Coverage Report - org.apache.maven.scm.provider.jazz.JazzScmProvider
 
Classes in this File Line Coverage Branch Coverage Complexity
JazzScmProvider
52 %
59/112
86 %
26/30
2,176
 
 1  
 package org.apache.maven.scm.provider.jazz;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.scm.CommandParameters;
 23  
 import org.apache.maven.scm.ScmException;
 24  
 import org.apache.maven.scm.ScmFileSet;
 25  
 import org.apache.maven.scm.command.add.AddScmResult;
 26  
 import org.apache.maven.scm.command.blame.BlameScmResult;
 27  
 import org.apache.maven.scm.command.branch.BranchScmResult;
 28  
 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
 29  
 import org.apache.maven.scm.command.checkin.CheckInScmResult;
 30  
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
 31  
 import org.apache.maven.scm.command.diff.DiffScmResult;
 32  
 import org.apache.maven.scm.command.edit.EditScmResult;
 33  
 import org.apache.maven.scm.command.export.ExportScmResult;
 34  
 import org.apache.maven.scm.command.list.ListScmResult;
 35  
 import org.apache.maven.scm.command.status.StatusScmResult;
 36  
 import org.apache.maven.scm.command.tag.TagScmResult;
 37  
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
 38  
 import org.apache.maven.scm.command.update.UpdateScmResult;
 39  
 import org.apache.maven.scm.provider.AbstractScmProvider;
 40  
 import org.apache.maven.scm.provider.ScmProviderRepository;
 41  
 import org.apache.maven.scm.provider.jazz.command.JazzConstants;
 42  
 import org.apache.maven.scm.provider.jazz.command.add.JazzAddCommand;
 43  
 import org.apache.maven.scm.provider.jazz.command.blame.JazzBlameCommand;
 44  
 import org.apache.maven.scm.provider.jazz.command.branch.JazzBranchCommand;
 45  
 import org.apache.maven.scm.provider.jazz.command.changelog.JazzChangeLogCommand;
 46  
 import org.apache.maven.scm.provider.jazz.command.checkin.JazzCheckInCommand;
 47  
 import org.apache.maven.scm.provider.jazz.command.checkout.JazzCheckOutCommand;
 48  
 import org.apache.maven.scm.provider.jazz.command.diff.JazzDiffCommand;
 49  
 import org.apache.maven.scm.provider.jazz.command.edit.JazzEditCommand;
 50  
 import org.apache.maven.scm.provider.jazz.command.list.JazzListCommand;
 51  
 import org.apache.maven.scm.provider.jazz.command.status.JazzStatusCommand;
 52  
 import org.apache.maven.scm.provider.jazz.command.tag.JazzTagCommand;
 53  
 import org.apache.maven.scm.provider.jazz.command.unedit.JazzUnEditCommand;
 54  
 import org.apache.maven.scm.provider.jazz.command.update.JazzUpdateCommand;
 55  
 import org.apache.maven.scm.provider.jazz.repository.JazzScmProviderRepository;
 56  
 import org.apache.maven.scm.repository.ScmRepositoryException;
 57  
 
 58  
 import java.net.URI;
 59  
 
 60  
 /**
 61  
  * The maven scm provider for Jazz.
 62  
  * <p/>
 63  
  * This provider is a wrapper for the command line tool, "scm.sh" or "scm.exe" is that is
 64  
  * part of the Jazz SCM Server.
 65  
  * <p/>
 66  
  * This provider does not use a native API to communicate with the Jazz SCM server.
 67  
  * <p/>
 68  
  * The scm tool itself is documented at:
 69  
  * V2.0.0  - http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_scm.html
 70  
  * V3.0    - http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_scm.html
 71  
  * V3.0.1  - http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_scm.html
 72  
  *
 73  
  * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a>
 74  
  * @plexus.component role="org.apache.maven.scm.provider.ScmProvider" role-hint="jazz"
 75  
  */
 76  25
 public class JazzScmProvider
 77  
     extends AbstractScmProvider
 78  
 {
 79  
     // Example: scm:jazz:daviddl;passw0rd123@https://localhost:9443/jazz:Dave's Repository Workspace
 80  
     // If the username or password is supplied, then the @ must be used to delimit them.
 81  
     public static final String JAZZ_URL_FORMAT =
 82  
         "scm:jazz:[username[;password]@]http[s]://server_name[:port]/contextRoot:repositoryWorkspace";
 83  
 
 84  
     // ----------------------------------------------------------------------
 85  
     // ScmProvider Implementation
 86  
     // ----------------------------------------------------------------------
 87  
 
 88  
     public String getScmType()
 89  
     {
 90  0
         return JazzConstants.SCM_TYPE;
 91  
     }
 92  
 
 93  
     /**
 94  
      * This method parses the scm URL and returns a SCM provider repository.
 95  
      * At this point, the scmUrl is the part after scm:provider_name: in your SCM URL.
 96  
      * <p/>
 97  
      * The basic url parsing approach is to be as loose as possible.
 98  
      * If you specify as per the docs you'll get what you expect.
 99  
      * If you do something else the result is undefined.
 100  
      * Don't use "/" "\" or "@" as the delimiter.
 101  
      * <p/>
 102  
      * Parse the scmUrl, which will be of the form:
 103  
      * [username[;password]@]http[s]://server_name[:port]/contextRoot:repositoryWorkspace
 104  
      * eg:
 105  
      * Deb;Deb@https://rtc:9444/jazz:BogusRepositoryWorkspace
 106  
      * {@inheritDoc}
 107  
      */
 108  
     public ScmProviderRepository makeProviderScmRepository( String scmUrl, char delimiter )
 109  
         throws ScmRepositoryException
 110  
     {
 111  
         // Called from:
 112  
         // AbstractScmProvider.makeScmRepository()
 113  
         // AbstractScmProvider.validateScmUrl()
 114  43
         getLogger().debug( "JazzScmProvider:makeProviderScmRepository" );
 115  43
         getLogger().debug( "Provided scm url   - " + scmUrl );
 116  43
         getLogger().debug( "Provided delimiter - '" + delimiter + "'" );
 117  
 
 118  43
         String jazzUrlAndWorkspace = null;
 119  43
         String usernameAndPassword = null;
 120  
 
 121  
         // Look for the Jazz URL after any '@' delimiter used to pass
 122  
         // username/password etc (which may not have been specified)
 123  43
         int lastAtPosition = scmUrl.lastIndexOf( '@' );
 124  43
         if ( lastAtPosition == -1 )
 125  
         {
 126  
             // The username;password@ was not supplied.
 127  13
             jazzUrlAndWorkspace = scmUrl;
 128  
         }
 129  
         else
 130  
         {
 131  
             // The username@ or username;password@ was supplied.
 132  30
             jazzUrlAndWorkspace = ( lastAtPosition < 0 ) ? scmUrl : scmUrl.substring( lastAtPosition + 1 );
 133  30
             usernameAndPassword = ( lastAtPosition < 0 ) ? null : scmUrl.substring( 0, lastAtPosition );
 134  
         }
 135  
 
 136  
         // jazzUrlAndWorkspace should be: http[s]://server_name:port/contextRoot:repositoryWorkspace
 137  
         // usernameAndPassword should be: username;password or null
 138  
 
 139  
         // username and password may not be supplied, and so may remain null.
 140  43
         String username = null;
 141  43
         String password = null;
 142  
 
 143  43
         if ( usernameAndPassword != null )
 144  
         {
 145  
             // Can be:
 146  
             // username
 147  
             // username;password
 148  30
             int delimPosition = usernameAndPassword.indexOf( ';' );
 149  30
             username = delimPosition >= 0 ? usernameAndPassword.substring( 0, delimPosition ) : usernameAndPassword;
 150  30
             password = delimPosition >= 0 ? usernameAndPassword.substring( delimPosition + 1 ) : null;
 151  
         }
 152  
 
 153  
         // We will now validate the jazzUrlAndWorkspace for right number of colons.
 154  
         // This has been observed in the wild, where the contextRoot:repositoryWorkspace was not properly formed
 155  
         // and this resulted in very strange results in the way in which things were parsed.
 156  43
         int colonsCounted = 0;
 157  43
         int colonIndex = 0;
 158  200
         while ( colonIndex != -1 )
 159  
         {
 160  157
             colonIndex = jazzUrlAndWorkspace.indexOf( ":", colonIndex + 1 );
 161  157
             if ( colonIndex != -1 )
 162  
             {
 163  114
                 colonsCounted++;
 164  
             }
 165  
         }
 166  
         // havePort may also be true when port is supplied, but otherwise have a malformed URL.
 167  43
         boolean havePort = colonsCounted == 3;
 168  
 
 169  
         // Look for workspace after the end of the Jazz URL
 170  43
         int repositoryWorkspacePosition = jazzUrlAndWorkspace.lastIndexOf( delimiter );
 171  43
         String repositoryWorkspace = jazzUrlAndWorkspace.substring( repositoryWorkspacePosition + 1 );
 172  43
         String jazzUrl = jazzUrlAndWorkspace.substring( 0, repositoryWorkspacePosition );
 173  
 
 174  
         // Validate the protocols.
 175  
         try
 176  
         {
 177  
             // Determine if it is a valid URI.
 178  43
             URI jazzUri = URI.create( jazzUrl );
 179  43
             String scheme = jazzUri.getScheme();
 180  43
             getLogger().debug( "Scheme - " + scheme );
 181  43
             if ( scheme == null || !( scheme.equalsIgnoreCase( "http" ) || scheme.equalsIgnoreCase( "https" ) ) )
 182  
             {
 183  4
                 throw new ScmRepositoryException(
 184  
                     "Jazz Url \"" + jazzUrl + "\" is not a valid URL. The Jazz Url syntax is " + JAZZ_URL_FORMAT );
 185  
             }
 186  
         }
 187  0
         catch ( IllegalArgumentException e )
 188  
         {
 189  0
             throw new ScmRepositoryException(
 190  
                 "Jazz Url \"" + jazzUrl + "\" is not a valid URL. The Jazz Url syntax is " + JAZZ_URL_FORMAT );
 191  39
         }
 192  
 
 193  
         // At this point, jazzUrl is guaranteed to start with either http:// or https://
 194  
         // Further process the jazzUrl to extract the server name and port.
 195  39
         String hostname = null;
 196  39
         int port = 0;
 197  
 
 198  39
         if ( havePort )
 199  
         {
 200  
             // jazzUrlAndWorkspace should be: http[s]://server_name:port/contextRoot:repositoryWorkspace
 201  
             // jazzUrl should be            : http[s]://server_name:port/contextRoot
 202  32
             int protocolIndex = jazzUrl.indexOf( ":" ) + 3;     // The +3 accounts for the "://"
 203  32
             int portIndex = jazzUrl.indexOf( ":", protocolIndex + 1 );
 204  32
             hostname = jazzUrl.substring( protocolIndex, portIndex );
 205  32
             int pathIndex = jazzUrl.indexOf( "/", portIndex + 1 );
 206  32
             String portNo = jazzUrl.substring( portIndex + 1, pathIndex );
 207  
             try
 208  
             {
 209  32
                 port = Integer.parseInt( portNo );
 210  
             }
 211  2
             catch ( NumberFormatException nfe )
 212  
             {
 213  2
                 throw new ScmRepositoryException(
 214  
                     "Jazz Url \"" + jazzUrl + "\" is not a valid URL. The Jazz Url syntax is " + JAZZ_URL_FORMAT );
 215  30
             }
 216  30
         }
 217  
         else
 218  
         {
 219  
             // jazzUrlAndWorkspace should be: http[s]://server_name/contextRoot:repositoryWorkspace
 220  
             // jazzUrl should be            : http[s]://server_name/contextRoot
 221  
             // So we will set port to zero.
 222  7
             int protocolIndex = jazzUrl.indexOf( ":" ) + 3;     // The +3 accounts for the "://"
 223  7
             int pathIndex = jazzUrl.indexOf( "/", protocolIndex + 1 );
 224  7
             if ( ( protocolIndex != -1 ) && ( pathIndex != -1 ) )
 225  
             {
 226  6
                 hostname = jazzUrl.substring( protocolIndex, pathIndex );
 227  
             }
 228  
             else
 229  
             {
 230  1
                 throw new ScmRepositoryException(
 231  
                     "Jazz Url \"" + jazzUrl + "\" is not a valid URL. The Jazz Url syntax is " + JAZZ_URL_FORMAT );
 232  
             }
 233  
         }
 234  
 
 235  36
         getLogger().debug( "Creating JazzScmProviderRepository with the following values:" );
 236  36
         getLogger().debug( "jazzUrl             - " + jazzUrl );
 237  36
         getLogger().debug( "username            - " + username );
 238  36
         getLogger().debug( "password            - " + password );
 239  36
         getLogger().debug( "hostname            - " + hostname );
 240  36
         getLogger().debug( "port                - " + port );
 241  36
         getLogger().debug( "repositoryWorkspace - " + repositoryWorkspace );
 242  
 
 243  36
         return new JazzScmProviderRepository( jazzUrl, username, password, hostname, port, repositoryWorkspace );
 244  
     }
 245  
 
 246  
     /**
 247  
      * {@inheritDoc}
 248  
      */
 249  
     public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 250  
         throws ScmException
 251  
     {
 252  0
         JazzAddCommand command = new JazzAddCommand();
 253  0
         command.setLogger( getLogger() );
 254  0
         return (AddScmResult) command.execute( repository, fileSet, parameters );
 255  
     }
 256  
 
 257  
     /**
 258  
      * {@inheritDoc}
 259  
      */
 260  
     protected BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet,
 261  
                                       CommandParameters parameters )
 262  
         throws ScmException
 263  
     {
 264  0
         JazzBranchCommand command = new JazzBranchCommand();
 265  0
         command.setLogger( getLogger() );
 266  0
         return (BranchScmResult) command.execute( repository, fileSet, parameters );
 267  
     }
 268  
 
 269  
     /**
 270  
      * {@inheritDoc}
 271  
      */
 272  
     protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 273  
         throws ScmException
 274  
     {
 275  0
         JazzBlameCommand command = new JazzBlameCommand();
 276  0
         command.setLogger( getLogger() );
 277  0
         return (BlameScmResult) command.execute( repository, fileSet, parameters );
 278  
     }
 279  
 
 280  
     /**
 281  
      * {@inheritDoc}
 282  
      */
 283  
     protected ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
 284  
                                             CommandParameters parameters )
 285  
         throws ScmException
 286  
     {
 287  
         // We need to call the status command first, so that we can get the details of the workspace.
 288  
         // This is needed for the list changesets command.
 289  
         // We could also 'trust' the value in the pom.
 290  0
         JazzStatusCommand statusCommand = new JazzStatusCommand();
 291  0
         statusCommand.setLogger( getLogger() );
 292  0
         statusCommand.execute( repository, fileSet, parameters );
 293  
 
 294  0
         JazzChangeLogCommand command = new JazzChangeLogCommand();
 295  0
         command.setLogger( getLogger() );
 296  0
         return (ChangeLogScmResult) command.execute( repository, fileSet, parameters );
 297  
     }
 298  
 
 299  
     /**
 300  
      * {@inheritDoc}
 301  
      */
 302  
     protected CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
 303  
                                         CommandParameters parameters )
 304  
         throws ScmException
 305  
     {
 306  0
         JazzCheckInCommand command = new JazzCheckInCommand();
 307  0
         command.setLogger( getLogger() );
 308  0
         return (CheckInScmResult) command.execute( repository, fileSet, parameters );
 309  
     }
 310  
 
 311  
     /**
 312  
      * {@inheritDoc}
 313  
      */
 314  
     protected CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
 315  
                                           CommandParameters parameters )
 316  
         throws ScmException
 317  
     {
 318  0
         JazzCheckOutCommand command = new JazzCheckOutCommand();
 319  0
         command.setLogger( getLogger() );
 320  0
         return (CheckOutScmResult) command.execute( repository, fileSet, parameters );
 321  
     }
 322  
 
 323  
     /**
 324  
      * {@inheritDoc}
 325  
      */
 326  
     protected DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 327  
         throws ScmException
 328  
     {
 329  0
         JazzDiffCommand command = new JazzDiffCommand();
 330  0
         command.setLogger( getLogger() );
 331  0
         return (DiffScmResult) command.execute( repository, fileSet, parameters );
 332  
     }
 333  
 
 334  
     /**
 335  
      * {@inheritDoc}
 336  
      */
 337  
     protected EditScmResult edit( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 338  
         throws ScmException
 339  
     {
 340  0
         JazzEditCommand command = new JazzEditCommand();
 341  0
         command.setLogger( getLogger() );
 342  0
         return (EditScmResult) command.execute( repository, fileSet, parameters );
 343  
     }
 344  
 
 345  
     /**
 346  
      * {@inheritDoc}
 347  
      */
 348  
     protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
 349  
                                       CommandParameters parameters )
 350  
         throws ScmException
 351  
     {
 352  
         // Use checkout instead
 353  0
         return super.export( repository, fileSet, parameters );
 354  
     }
 355  
 
 356  
     /**
 357  
      * {@inheritDoc}
 358  
      */
 359  
     protected ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 360  
         throws ScmException
 361  
     {
 362  
         // We need to call the status command first, so that we can get the details of the stream etc.
 363  
         // This is needed for workspace deliveries and snapshot promotions.
 364  0
         JazzStatusCommand statusCommand = new JazzStatusCommand();
 365  0
         statusCommand.setLogger( getLogger() );
 366  0
         statusCommand.execute( repository, fileSet, parameters );
 367  
 
 368  0
         JazzListCommand command = new JazzListCommand();
 369  0
         command.setLogger( getLogger() );
 370  0
         return (ListScmResult) command.execute( repository, fileSet, parameters );
 371  
     }
 372  
 
 373  
     /**
 374  
      * {@inheritDoc}
 375  
      */
 376  
     protected StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet,
 377  
                                       CommandParameters parameters )
 378  
         throws ScmException
 379  
     {
 380  0
         JazzStatusCommand command = new JazzStatusCommand();
 381  0
         command.setLogger( getLogger() );
 382  0
         return (StatusScmResult) command.execute( repository, fileSet, parameters );
 383  
     }
 384  
 
 385  
     /**
 386  
      * {@inheritDoc}
 387  
      */
 388  
     protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
 389  
         throws ScmException
 390  
     {
 391  
         // We need to call the status command first, so that we can get the details of the stream etc.
 392  
         // This is needed for workspace deliveries and snapshot promotions.
 393  0
         JazzStatusCommand statusCommand = new JazzStatusCommand();
 394  0
         statusCommand.setLogger( getLogger() );
 395  0
         statusCommand.execute( repository, fileSet, parameters );
 396  
 
 397  0
         JazzTagCommand command = new JazzTagCommand();
 398  0
         command.setLogger( getLogger() );
 399  0
         return (TagScmResult) command.execute( repository, fileSet, parameters );
 400  
     }
 401  
 
 402  
     /**
 403  
      * {@inheritDoc}
 404  
      */
 405  
     protected UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet,
 406  
                                       CommandParameters parameters )
 407  
         throws ScmException
 408  
     {
 409  0
         JazzUpdateCommand command = new JazzUpdateCommand();
 410  0
         command.setLogger( getLogger() );
 411  0
         return (UpdateScmResult) command.execute( repository, fileSet, parameters );
 412  
     }
 413  
 
 414  
     /**
 415  
      * {@inheritDoc}
 416  
      */
 417  
     protected UnEditScmResult unedit( ScmProviderRepository repository, ScmFileSet fileSet,
 418  
                                       CommandParameters parameters )
 419  
         throws ScmException
 420  
     {
 421  0
         JazzUnEditCommand command = new JazzUnEditCommand();
 422  0
         command.setLogger( getLogger() );
 423  0
         return (UnEditScmResult) command.execute( repository, fileSet, parameters );
 424  
     }
 425  
 
 426  
     /**
 427  
      * {@inheritDoc}
 428  
      */
 429  
     public String getScmSpecificFilename()
 430  
     {
 431  0
         return JazzConstants.SCM_META_DATA_FOLDER;
 432  
     }
 433  
 
 434  
 }