Coverage Report - org.apache.maven.wagon.mercury.MercuryWagon
 
Classes in this File Line Coverage Branch Coverage Complexity
MercuryWagon
0 %
0/209
0 %
0/80
0
 
 1  
 package org.apache.maven.wagon.mercury;
 2  
 
 3  
 import java.io.File;
 4  
 import java.io.FileInputStream;
 5  
 import java.io.FileNotFoundException;
 6  
 import java.io.IOException;
 7  
 import java.net.MalformedURLException;
 8  
 import java.net.URL;
 9  
 import java.util.ArrayList;
 10  
 import java.util.HashSet;
 11  
 import java.util.List;
 12  
 import java.util.Properties;
 13  
 import java.util.Set;
 14  
 
 15  
 import org.apache.maven.mercury.crypto.api.StreamObserverFactory;
 16  
 import org.apache.maven.mercury.crypto.api.StreamVerifierAttributes;
 17  
 import org.apache.maven.mercury.crypto.api.StreamVerifierException;
 18  
 import org.apache.maven.mercury.crypto.api.StreamVerifierFactory;
 19  
 import org.apache.maven.mercury.crypto.pgp.PgpStreamVerifierFactory;
 20  
 import org.apache.maven.mercury.spi.http.client.HttpClientException;
 21  
 import org.apache.maven.mercury.spi.http.client.deploy.DefaultDeployRequest;
 22  
 import org.apache.maven.mercury.spi.http.client.deploy.DefaultDeployer;
 23  
 import org.apache.maven.mercury.spi.http.client.deploy.DeployResponse;
 24  
 import org.apache.maven.mercury.spi.http.client.retrieve.DefaultRetrievalRequest;
 25  
 import org.apache.maven.mercury.spi.http.client.retrieve.DefaultRetriever;
 26  
 import org.apache.maven.mercury.spi.http.client.retrieve.RetrievalResponse;
 27  
 import org.apache.maven.mercury.transport.api.Binding;
 28  
 import org.apache.maven.mercury.transport.api.Credentials;
 29  
 import org.apache.maven.mercury.transport.api.Server;
 30  
 import org.apache.maven.wagon.AbstractWagon;
 31  
 import org.apache.maven.wagon.ConnectionException;
 32  
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 33  
 import org.apache.maven.wagon.TransferFailedException;
 34  
 import org.apache.maven.wagon.Wagon;
 35  
 import org.apache.maven.wagon.authentication.AuthenticationException;
 36  
 import org.apache.maven.wagon.authorization.AuthorizationException;
 37  
 import org.apache.maven.wagon.events.TransferEvent;
 38  
 import org.apache.maven.wagon.proxy.ProxyInfo;
 39  
 import org.apache.maven.wagon.resource.Resource;
 40  
 import org.codehaus.plexus.lang.DefaultLanguage;
 41  
 import org.codehaus.plexus.lang.Language;
 42  
 import org.slf4j.Logger;
 43  
 import org.slf4j.LoggerFactory;
 44  
 
 45  
 /**
 46  
  *  plexus.component
 47  
  *    role-hint="http"
 48  
  *    instantiation-strategy="per-lookup"
 49  
  *    description="Mercury based wagon implementation"
 50  
  *
 51  
  * @author Oleg Gusakov
 52  
  * @version $Id$
 53  
  *
 54  
  */
 55  
 public class MercuryWagon
 56  
 extends AbstractWagon
 57  
 implements Wagon
 58  
 {
 59  
   public static final String SYSTEM_PARAMETER_DEBUG_TRANSFER = "maven.mercury.wagon.debug.transfer";
 60  0
   private boolean debugTransfer = Boolean.parseBoolean( System.getProperty( SYSTEM_PARAMETER_DEBUG_TRANSFER, "false" ) );
 61  
 
 62  
   public static final String SYSTEM_PARAMETER_PGP_CONGIG = "maven.mercury.wagon.pgp.config";
 63  0
   private String pgpConfig = System.getProperty( SYSTEM_PARAMETER_PGP_CONGIG, null );
 64  
   
 65  
   // TODO: Oleg, 2008-09-26: move to mercury-transport-api 
 66  0
   public static final String [][] protocolConversions = new String [][]
 67  
                                                                       {
 68  
       {"http:",      "http:"}
 69  
     , {"https:",     "https:"}
 70  
     , {"dav:",       "http:"}
 71  
     , {"davs:",      "https:"}
 72  
     , {"dav:http:",  "http:"}
 73  
     , {"dav:https:", "https:"}
 74  
     , {"mttp:",      "http:"}
 75  
     , {"mttps:",     "https:"}
 76  
                                                                       };
 77  
 
 78  0
   private static final Logger _log = LoggerFactory.getLogger(MercuryWagon.class);
 79  0
   private static final Language _lang = new DefaultLanguage( MercuryWagon.class );
 80  
   
 81  
   private Server server;
 82  
   private DefaultRetriever retriever;
 83  
   private DefaultDeployer deployer;
 84  
   
 85  0
   private List<TransferEvent> events = new ArrayList<TransferEvent>(8);
 86  
   private String userAgent;
 87  
   
 88  
   /**
 89  
    * 
 90  
    */
 91  
   public MercuryWagon()
 92  0
   {
 93  0
     if( _log.isDebugEnabled() )
 94  0
       _log.debug( "MercuryWagon instantiated" );
 95  0
   }
 96  
   
 97  
   public MercuryWagon( Server server )
 98  
   throws IllegalArgumentException
 99  0
   {
 100  0
     init( server );
 101  0
   }
 102  
 
 103  
   private void init( Server server )
 104  
   throws IllegalArgumentException
 105  
   {
 106  0
     if( server == null )
 107  0
       throw new IllegalArgumentException( _lang.getMessage( "null.read.server" ) );
 108  
     
 109  0
     if( server.getURL() == null )
 110  0
       throw new IllegalArgumentException( _lang.getMessage( "null.read.server.url", server.getId() ) );
 111  
     
 112  0
     this.server = server;
 113  
     
 114  0
     Set<StreamVerifierFactory>[] pgpFac = null;
 115  
     
 116  
     try
 117  
     {
 118  0
       pgpFac = readPgpConfig();
 119  0
       this.server.setReaderStreamVerifierFactories( pgpFac[0] );
 120  0
       this.server.setWriterStreamVerifierFactories( pgpFac[1] );
 121  
     }
 122  0
     catch( Exception ex )
 123  
     {
 124  0
       throw new IllegalArgumentException(ex);
 125  0
     }
 126  
 
 127  0
     Set<StreamObserverFactory> rf = server.getReaderStreamObserverFactories();
 128  0
     if( rf == null )
 129  
     {
 130  0
       rf = new HashSet<StreamObserverFactory>(1);
 131  0
       this.server.setReaderStreamObserverFactories( rf );
 132  
     }
 133  0
     rf.add( new StupidWagonObserverFactory( this ) );
 134  
     
 135  0
     HashSet<Server> servers = new HashSet<Server>(1);
 136  0
     servers.add( this.server );
 137  
     
 138  0
     Set<StreamObserverFactory> wf = this.server.getWriterStreamObserverFactories();
 139  0
     if( wf == null )
 140  
     {
 141  0
       wf = new HashSet<StreamObserverFactory>(1);
 142  0
       this.server.setReaderStreamObserverFactories( wf );
 143  
     }
 144  0
     wf.add( new StupidWagonObserverFactory( this ) );
 145  
 
 146  
     try
 147  
     {
 148  0
       retriever = new DefaultRetriever();
 149  
     }
 150  0
     catch( HttpClientException e )
 151  
     {
 152  0
       throw new IllegalArgumentException(e);
 153  0
     }
 154  0
     retriever.setServers( servers );
 155  
     
 156  
     try
 157  
     {
 158  0
       deployer = new DefaultDeployer();
 159  
     }
 160  0
     catch( HttpClientException e )
 161  
     {
 162  0
       throw new IllegalArgumentException(e);
 163  0
     }
 164  0
     deployer.setServers( servers );
 165  0
   }
 166  
 
 167  
   public void get( String resourceName, File destination )
 168  
   throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 169  
   {
 170  0
     if( _log.isDebugEnabled() )
 171  0
       _log.debug("MercuryWagon getting "+resourceName+" into "+destination);
 172  
 
 173  0
     Binding binding = null;
 174  
     
 175  
     try
 176  
     {
 177  0
       binding = new Binding( new URL(server.getURL().toString()+'/'+resourceName), destination );
 178  
     }
 179  0
     catch( MalformedURLException e )
 180  
     {
 181  0
       throw new TransferFailedException( e.getMessage() );
 182  0
     }
 183  
     
 184  0
     DefaultRetrievalRequest request = new DefaultRetrievalRequest();
 185  0
     request.addBinding( binding );
 186  
     
 187  0
     Resource resource = new Resource( resourceName );
 188  
 
 189  0
     fireGetInitiated( resource, destination );
 190  
 
 191  0
     resource.setLastModified( 0l );
 192  
 
 193  0
     server.setUserAgent( userAgent );
 194  
 
 195  0
     fireGetStarted( resource, destination );
 196  
     
 197  0
     pushEvent( new TransferEvent(this, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_GET) );
 198  
     
 199  0
     long start = System.currentTimeMillis();
 200  
     
 201  0
     RetrievalResponse response = retriever.retrieve( request );
 202  
     
 203  0
     fireGetCompleted( resource, destination );
 204  
 
 205  0
     if( response.hasExceptions() )
 206  
     {
 207  0
       _log.error( response.getExceptions().toString() );
 208  0
       throw new ResourceDoesNotExistException( response.getExceptions().toString() );
 209  
     }
 210  
 
 211  0
     if( _log.isDebugEnabled() )
 212  0
       _log.debug("MercuryWagon got ["+resourceName+" ==> "+destination + "], time " + (System.currentTimeMillis()-start) + " millis");
 213  
     
 214  0
   }
 215  
 
 216  
   public boolean getIfNewer( String resourceName, File destination, long timestamp )
 217  
   throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 218  
   {
 219  0
     get( resourceName, destination );
 220  0
     return true;
 221  
   }
 222  
 
 223  
   public void put( File source, String destination )
 224  
   throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 225  
   {
 226  0
     if( _log.isDebugEnabled() )
 227  0
       _log.debug( "put request for: "+source+" => "+destination );
 228  
 
 229  0
     Resource resource = new Resource( destination );
 230  
     
 231  0
     firePutInitiated( resource, source );
 232  
     
 233  0
     resource.setContentLength( source.length() );
 234  
     
 235  0
     resource.setLastModified( source.lastModified() );
 236  
 
 237  0
     Binding binding = null;
 238  
     try
 239  
     {
 240  0
       binding = new Binding( new URL( this.server.getURL().toString()+'/'+destination), source );
 241  
     }
 242  0
     catch( MalformedURLException e )
 243  
     {
 244  0
       throw new TransferFailedException( e.getMessage() );
 245  0
     }
 246  
     
 247  0
     HashSet<Binding> bindings = new HashSet<Binding>(1);
 248  0
     bindings.add( binding );
 249  
     
 250  0
     DefaultDeployRequest request = new DefaultDeployRequest();
 251  0
     request.setBindings( bindings );
 252  
 
 253  0
     firePutStarted( resource, source );
 254  
     
 255  0
     server.setUserAgent( userAgent );
 256  
 
 257  0
     pushEvent( new TransferEvent(this, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT) );
 258  
     
 259  0
     long start = System.currentTimeMillis();
 260  
 
 261  0
     DeployResponse response = deployer.deploy( request );
 262  
 
 263  0
     firePutCompleted( resource, source );
 264  
 
 265  0
     if( response.hasExceptions() )
 266  
     {
 267  0
       throw new TransferFailedException( response.getExceptions().toString() );
 268  
     }
 269  
 
 270  0
     if( _log.isDebugEnabled() )
 271  0
       _log.debug("MercuryWagon put ["+source+" ==> "+destination + "], time " + (System.currentTimeMillis()-start) + " millis");
 272  0
   }
 273  
 
 274  
   protected void closeConnection()
 275  
   throws ConnectionException
 276  
   {
 277  0
   }
 278  
   
 279  
   @Override
 280  
   public void openConnection()
 281  
   throws ConnectionException, AuthenticationException
 282  
   {
 283  0
     openConnectionInternal();
 284  0
   }
 285  
   
 286  
   private final String convertProtocol( String pin )
 287  
   throws ConnectionException
 288  
   {
 289  0
     for( String [] pc : protocolConversions )
 290  
     {
 291  0
       if( pc[0].equals( pin ) )
 292  0
         return pc[1];
 293  
     }
 294  
     
 295  0
     throw new ConnectionException("bad protocol: "+pin);
 296  
   }
 297  
   
 298  
   @Override
 299  
   protected void openConnectionInternal()
 300  
   throws ConnectionException, AuthenticationException
 301  
   {
 302  0
     if( _log.isDebugEnabled() )
 303  0
       _log.debug( "opening connection to repository "+repository );
 304  
 
 305  
     try
 306  
     {
 307  0
       String repUrl = repository.getUrl();
 308  0
       int index = repUrl.indexOf( '/' );
 309  0
       String protocol =  convertProtocol( repUrl.substring( 0, index  ) );
 310  
 
 311  0
       String theRest = repUrl.substring( index );
 312  0
       if( theRest.endsWith( "/" ) )
 313  0
         theRest = theRest.substring( 0, theRest.length()-1 );
 314  
 
 315  0
       String url = protocol + theRest;
 316  
 
 317  0
       if(_log.isDebugEnabled())
 318  0
         _log.debug( "converted url "+repository.getUrl()+" ==> "+url );
 319  
 
 320  0
       Server server = new Server( repository.getId(), new URL( url ) );
 321  
 
 322  0
       if( authenticationInfo != null && authenticationInfo.getUserName() != null )
 323  
       {
 324  0
         Credentials user = new Credentials( authenticationInfo.getUserName(), authenticationInfo.getPassword() );
 325  
         
 326  0
         server.setServerCredentials( user );
 327  
         
 328  0
         if( _log.isDebugEnabled() )
 329  0
           _log.debug( "user ceredentials: "+user.getUser()+"/..." );
 330  
       }
 331  
       
 332  
       
 333  0
       ProxyInfo pi = getProxyInfo("http", getRepository().getHost());
 334  
 
 335  0
       String httpProxyType = ProxyInfo.PROXY_HTTP.toLowerCase(); 
 336  
 
 337  0
       if( pi != null && pi.getHost() != null )
 338  
       {
 339  0
         String proxyType = pi.getType().toLowerCase();
 340  
         
 341  0
         if( !httpProxyType.equals( proxyType ) )
 342  
         {
 343  0
           throw new ConnectionException( "Mercury wagon does not support "+proxyType+" proxies at this point. Only "+httpProxyType+" proxy is supported" );
 344  
         }
 345  
 
 346  0
         server.setProxy( new URL("http://"+pi.getHost()+":" + (pi.getPort()>0 ? pi.getPort() : 80) ) );
 347  
 
 348  0
         if( pi.getUserName() != null )
 349  
         {
 350  0
           Credentials proxyUser = new Credentials( pi.getUserName(), pi.getPassword() );
 351  
           
 352  0
           server.setProxyCredentials( proxyUser );
 353  
 
 354  0
           if(_log.isDebugEnabled())
 355  0
             _log.debug( "proxy credentials set to : " + proxyUser.getUser()+"/..." );
 356  
         }
 357  
       }
 358  
 
 359  0
       if(_log.isDebugEnabled())
 360  0
         _log.debug( "proxy url set to : " + server.getProxy() );
 361  
 
 362  0
       init( server );
 363  
       
 364  0
       if( debugTransfer )
 365  0
         transferEventSupport.addTransferListener( new TransferEventDebugger() );
 366  
     }
 367  
 //    catch( MalformedURLException e )
 368  
 //    {
 369  
 //      throw new ConnectionException( e.getMessage() );
 370  
 //    }
 371  0
     catch( Throwable e )
 372  
     {
 373  0
       e.printStackTrace();
 374  0
       _log.error( e.getMessage() );
 375  0
       throw new ConnectionException( e.getMessage() );
 376  0
     }
 377  0
   }
 378  
 
 379  
   void bytesReady( TransferEvent transferEvent, byte [] buf, int len )
 380  
   {
 381  0
     fireTransferProgress( transferEvent, buf, len );
 382  0
   }
 383  
 
 384  
   /**
 385  
    * @return
 386  
    */
 387  
   public final TransferEvent popEvent()
 388  
   {
 389  0
     if( events.isEmpty() )
 390  0
       return null;
 391  
     
 392  0
     TransferEvent event = events.get( 0 );
 393  0
     events.remove( 0 );
 394  
     
 395  0
     return event;
 396  
   }
 397  
 
 398  
   public final void pushEvent( final TransferEvent event)
 399  
   {
 400  0
     events.add( 0, event );
 401  0
   }
 402  
   
 403  
   private final Set<StreamVerifierFactory>[] readPgpConfig()
 404  
   throws FileNotFoundException, IOException, StreamVerifierException
 405  
   {
 406  0
     Set<StreamVerifierFactory> [] res = new Set [] { null, null };
 407  
     
 408  0
     if( pgpConfig == null )
 409  0
       return res;
 410  
     
 411  0
     if( _log.isDebugEnabled() )
 412  0
       _log.debug( "PGP signature configuration will be read from "+pgpConfig );
 413  
     
 414  0
     Properties pgpProps = new Properties();
 415  0
     pgpProps.load( new FileInputStream(pgpConfig) );
 416  
 
 417  0
     String readerKeyring = pgpProps.getProperty( "reader.keyring" );
 418  
     
 419  0
     if( readerKeyring != null )
 420  
     {
 421  0
       StreamVerifierAttributes readerAttr = new StreamVerifierAttributes(
 422  
           PgpStreamVerifierFactory.DEFAULT_EXTENSION
 423  
         , Boolean.parseBoolean( pgpProps.getProperty( "reader.lenient", "true" ) )
 424  
         , false
 425  
                                                                       );
 426  
 
 427  0
       StreamVerifierFactory rf = new PgpStreamVerifierFactory( readerAttr, new FileInputStream(readerKeyring) );
 428  
 
 429  0
       if( _log.isDebugEnabled() )
 430  0
         _log.debug( "public key file: "+new File(readerKeyring).getAbsolutePath() );
 431  
       
 432  0
       Set<StreamVerifierFactory> rs = new HashSet<StreamVerifierFactory>(1);
 433  0
       rs.add( rf );
 434  0
       res[0] = rs;
 435  
     }
 436  
 
 437  0
     String writerKeyring = pgpProps.getProperty( "writer.keyring" );
 438  0
     String writerKeyId = pgpProps.getProperty( "writer.key.id" );
 439  0
     String writerKeyringPass = pgpProps.getProperty( "writer.key.pass" );
 440  
 
 441  0
     if( writerKeyring != null && writerKeyId != null && writerKeyringPass != null )
 442  
     {
 443  0
       if( _log.isDebugEnabled() )
 444  0
         _log.debug( "secret key file: "+new File(writerKeyring).getAbsolutePath() );
 445  
 
 446  0
       StreamVerifierAttributes writerAttr = new StreamVerifierAttributes(
 447  
           PgpStreamVerifierFactory.DEFAULT_EXTENSION
 448  
         , Boolean.parseBoolean( pgpProps.getProperty( "writer.lenient", "true" ) )
 449  
         , false
 450  
                                                                       );
 451  
 
 452  0
       StreamVerifierFactory wf = new PgpStreamVerifierFactory( writerAttr, new FileInputStream(writerKeyring)
 453  
                                                               , writerKeyId, writerKeyringPass );
 454  
       
 455  0
       Set<StreamVerifierFactory> ws = new HashSet<StreamVerifierFactory>(1);
 456  0
       ws.add( wf );
 457  0
       res[1] = ws;
 458  
     }
 459  
     
 460  0
     return res;
 461  
   }
 462  
   
 463  
   public void setHttpHeaders( Properties httpHeaders )
 464  
   {
 465  0
       this.userAgent = httpHeaders.getProperty( "User-Agent", null );
 466  
       
 467  0
       if( _log.isDebugEnabled() )
 468  0
         _log.debug( "userAgent set to : "+this.userAgent );
 469  
       
 470  0
   }
 471  
 
 472  
   @Override
 473  
   public boolean resourceExists( String resourceName )
 474  
   throws TransferFailedException, AuthorizationException
 475  
   {
 476  0
     if( _log.isDebugEnabled() )
 477  0
       _log.debug( "check if resourceExists: "+resourceName+" on server "+(server == null ? "null" : server.getURL() ) );
 478  
 
 479  
     File temp;
 480  
     try
 481  
     {
 482  0
       temp = File.createTempFile( "mercury-", ".temp" );
 483  
     }
 484  0
     catch( IOException e )
 485  
     {
 486  0
       throw new TransferFailedException( e.getMessage() );
 487  0
     }
 488  0
     temp.delete();
 489  
     
 490  0
     Binding binding = null;
 491  
     
 492  
     try
 493  
     {
 494  0
       binding = new Binding( new URL(server.getURL().toString()+'/'+resourceName), temp );
 495  
     }
 496  0
     catch( MalformedURLException e )
 497  
     {
 498  0
       throw new TransferFailedException( e.getMessage() );
 499  0
     }
 500  
     
 501  0
     DefaultRetrievalRequest request = new DefaultRetrievalRequest();
 502  0
     request.addBinding( binding );
 503  
     
 504  0
     server.setUserAgent( userAgent );
 505  
 
 506  0
     RetrievalResponse response = retriever.retrieve( request );
 507  
     
 508  0
     temp.delete();
 509  
     
 510  0
     if( response.hasExceptions() )
 511  
     {
 512  0
       _log.error( response.getExceptions().toString() );
 513  0
       return false;
 514  
     }
 515  0
     return true;
 516  
   }
 517  
   
 518  
   
 519  
 
 520  
 }