public synchronized RepositoryConnectResult connect( final String username, final String password )
    throws KettleException {
    if ( serviceManager != null ) {
      disconnect();
    }
    serviceManager = new WebServiceManager( repositoryMeta.getRepositoryLocation().getUrl(), username );
    RepositoryServiceRegistry purRepositoryServiceRegistry = new RepositoryServiceRegistry();
    IUser user1 = new EEUserInfo();
    final String decryptedPassword = Encr.decryptPasswordOptionallyEncrypted( password );
    final RepositoryConnectResult result = new RepositoryConnectResult( purRepositoryServiceRegistry );
    try {
      final String urlEncodedPassword = encodePassword( decryptedPassword );
      /*
       * Three scenarios: 1. Connect in process: username fetched using PentahoSessionHolder; no authentication occurs
       * 2. Connect externally with trust: username specified is assumed authenticated if IP of calling code is trusted
       * 3. Connect externally: authentication occurs normally (i.e. password is checked)
       */
      user1.setLogin( username );
      user1.setPassword( urlEncodedPassword );
      user1.setName( username );
      result.setUser( user1 );

      // We need to have the application context and the session available in order for us to skip authentication
      if ( PentahoSystem.getApplicationContext() != null && PentahoSessionHolder.getSession() != null
          && PentahoSessionHolder.getSession().isAuthenticated() ) {
        if ( inProcess() ) {
          // connect to the IUnifiedRepository through PentahoSystem
          // this assumes we're running in a BI Platform
          result.setUnifiedRepository( PentahoSystem.get( IUnifiedRepository.class ) );
          if ( result.getUnifiedRepository() != null ) {
            if ( log.isDebug() ) {
              log.logDebug( BaseMessages.getString( PKG, "PurRepositoryConnector.ConnectInProgress.Begin" ) );
            }
            String name = PentahoSessionHolder.getSession().getName();
            user1 = new EEUserInfo();
            user1.setLogin( name );
            user1.setName( name );
            user1.setPassword( urlEncodedPassword );
            result.setUser( user1 );
            result.setSuccess( true );
            result.getUser().setAdmin(
              PentahoSystem.get( IAuthorizationPolicy.class ).isAllowed(
                IAbsSecurityProvider.ADMINISTER_SECURITY_ACTION )
            );

            if ( log.isDebug() ) {
              log.logDebug( BaseMessages.getString(
                      PKG, "PurRepositoryConnector.ConnectInProgress", name, result.getUnifiedRepository() ) );
            }

            // for now, there is no need to support the security manager
            // what about security provider?
            return result;
          }
        }
      }

      ExecutorService executor = getExecutor();

      Future<Boolean> authorizationWebserviceFuture = executor.submit( new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
          // We need to add the service class in the list in the order of dependencies
          // IRoleSupportSecurityManager depends RepositorySecurityManager to be present
          if ( log.isBasic() ) {
            log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateServiceProvider.Start" ) );
          }
          result.setSecurityProvider( new AbsSecurityProvider( purRepository, repositoryMeta, result.getUser(),
              serviceManager ) );
          if ( log.isBasic() ) {
            log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateServiceProvider.End" ) ); //$NON-NLS-1$
          }

          // If the user does not have access to administer security we do not
          // need to added them to the service list
          if ( allowedActionsContains( (AbsSecurityProvider) result.getSecurityProvider(),
              IAbsSecurityProvider.ADMINISTER_SECURITY_ACTION ) ) {
            result.setSecurityManager( new AbsSecurityManager( purRepository, repositoryMeta, result.getUser(),
                serviceManager ) );
            // Set the reference of the security manager to security provider for user role list change event
            ( (PurRepositorySecurityProvider) result.getSecurityProvider() )
                .setUserRoleDelegate( ( (PurRepositorySecurityManager) result.getSecurityManager() )
                    .getUserRoleDelegate() );
            return true;
          }
          return false;
        }
      } );

      Future<WebServiceException> repoWebServiceFuture = executor.submit( new Callable<WebServiceException>() {

        @Override
        public WebServiceException call() throws Exception {
          try {
            IUnifiedRepositoryJaxwsWebService repoWebService = null;
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateRepositoryWebService.Start" ) ); //$NON-NLS-1$
            }
            repoWebService =
                serviceManager.createService( username, urlEncodedPassword, IUnifiedRepositoryJaxwsWebService.class ); //$NON-NLS-1$
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateRepositoryWebService.End" ) ); //$NON-NLS-1$
            }
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateUnifiedRepositoryToWebServiceAdapter.Start" ) ); //$NON-NLS-1$
            }
            result.setUnifiedRepository( new UnifiedRepositoryToWebServiceAdapter( repoWebService ) );
          } catch ( WebServiceException wse ) {
            return wse;
          }
          return null;
        }
      } );

      Future<Exception> syncWebserviceFuture = executor.submit( new Callable<Exception>() {

        @Override
        public Exception call() throws Exception {
          try {
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateRepositorySyncWebService.Start" ) );
            }
            IRepositorySyncWebService syncWebService =
                serviceManager.createService( username, urlEncodedPassword, IRepositorySyncWebService.class ); //$NON-NLS-1$
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.CreateRepositorySyncWebService.Sync" ) ); //$NON-NLS-1$
            }
            syncWebService.sync( repositoryMeta.getName(), repositoryMeta.getRepositoryLocation().getUrl() );
          } catch ( RepositorySyncException e ) {
            log.logError( e.getMessage(), e );
            // this message will be presented to the user in spoon
            result.setConnectMessage( e.getMessage() );
            return null;
          } catch ( WebServiceException e ) {
            // if we can speak to the repository okay but not the sync service, assume we're talking to a BA Server
            log.logError( e.getMessage(), e );
            return new Exception( BaseMessages.getString( PKG, "PurRepository.BAServerLogin.Message" ), e );
          }
          return null;
        }
      } );

      Future<String> sessionServiceFuture = executor.submit( new Callable<String>() {

        @Override
        public String call() throws Exception {
          try {
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.SessionService.Start" ) );
            }
            CredentialsProvider provider = new BasicCredentialsProvider();
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( username, urlEncodedPassword );
            provider.setCredentials( AuthScope.ANY, credentials );
            HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider( provider ).build();
            HttpGet method = new HttpGet( repositoryMeta.getRepositoryLocation().getUrl() + "/api/session/userName" );
            if ( StringUtils.isNotBlank( System.getProperty( "pentaho.repository.client.attemptTrust" ) ) ) {
              method.addHeader( TRUST_USER, username );
            }
            HttpResponse response = client.execute( method );
            if ( log.isBasic() ) {
              log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.SessionService.Sync" ) );
            }
            return EntityUtils.toString( response.getEntity() );
          } catch ( Exception e ) {
            if ( log.isError() ) {
              log.logError( BaseMessages.getString( PKG, "PurRepositoryConnector.Error.EnableToGetUser" ), e );
            }
            return null;
          }
        }
      } );

      WebServiceException repoException = repoWebServiceFuture.get();
      if ( repoException != null ) {
        log.logError( repoException.getMessage() );
        throw new Exception( BaseMessages.getString( PKG, "PurRepository.FailedLogin.Message" ), repoException );
      }

      Exception syncException = syncWebserviceFuture.get();
      if ( syncException != null ) {
        throw syncException;
      }

      Boolean isAdmin = authorizationWebserviceFuture.get();
      result.getUser().setAdmin( isAdmin );


      String userName = sessionServiceFuture.get();
      if ( userName != null ) {
        result.getUser().setLogin( userName );
      }
      if ( log.isBasic() ) {
        log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.RegisterSecurityProvider.Start" ) );
      }
      purRepositoryServiceRegistry.registerService( RepositorySecurityProvider.class, result.getSecurityProvider() );
      purRepositoryServiceRegistry.registerService( IAbsSecurityProvider.class, result.getSecurityProvider() );
      if ( isAdmin ) {
        purRepositoryServiceRegistry.registerService( RepositorySecurityManager.class, result.getSecurityManager() );
        purRepositoryServiceRegistry.registerService( IRoleSupportSecurityManager.class, result.getSecurityManager() );
        purRepositoryServiceRegistry.registerService( IAbsSecurityManager.class, result.getSecurityManager() );
      }

      purRepositoryServiceRegistry.registerService( PurRepositoryRestService.PurRepositoryPluginApiRevision.class,
          serviceManager.createService( username, urlEncodedPassword,
              PurRepositoryRestService.PurRepositoryPluginApiRevision.class ) );

      purRepositoryServiceRegistry.registerService( IRevisionService.class, new UnifiedRepositoryRevisionService(
          result.getUnifiedRepository(), rootRef ) );
      purRepositoryServiceRegistry.registerService( IAclService.class, new UnifiedRepositoryConnectionAclService(
          result.getUnifiedRepository() ) );
      purRepositoryServiceRegistry.registerService( IConnectionAclService.class,
          new UnifiedRepositoryConnectionAclService( result.getUnifiedRepository() ) );
      purRepositoryServiceRegistry.registerService( ITrashService.class, new UnifiedRepositoryTrashService( result
          .getUnifiedRepository(), rootRef ) );
      purRepositoryServiceRegistry.registerService( ILockService.class, new UnifiedRepositoryLockService( result
          .getUnifiedRepository() ) );

      if ( log.isBasic() ) {
        log.logBasic( BaseMessages.getString( PKG, "PurRepositoryConnector.RepositoryServicesRegistered.End" ) );
      }

      result.setSuccess( true );
    } catch ( NullPointerException | UnsupportedEncodingException e ) {
      result.setSuccess( false );
      throw new KettleException( BaseMessages.getString( PKG, "PurRepository.LoginException.Message" ) );
    } catch ( Throwable e ) {
      result.setSuccess( false );
      serviceManager.close();
      throw new KettleException( e );
    }
    return result;
  }
@Test
  public void testConnect() {
    PurRepository mockPurRepository = mock( PurRepository.class );
    PurRepositoryMeta mockPurRepositoryMeta = mock( PurRepositoryMeta.class );
    PurRepositoryLocation location = mock( PurRepositoryLocation.class );
    RootRef mockRootRef = mock( RootRef.class );
    PurRepositoryConnector purRepositoryConnector =
      spy( new PurRepositoryConnector( mockPurRepository, mockPurRepositoryMeta, mockRootRef ) );
    doReturn( location ).when( mockPurRepositoryMeta ).getRepositoryLocation();
    doReturn( "" ).when( location ).getUrl();
    ExecutorService service = mock( ExecutorService.class );
    doReturn( service ).when( purRepositoryConnector ).getExecutor();
    Future future = mock( Future.class );
    try {
      doReturn( "U1" ).when( future ).get();
    } catch ( Exception e ) {
      e.printStackTrace();
    }
    Future future2 = mock( Future.class );
    try {
      doReturn( false ).when( future2 ).get();
    } catch ( Exception e ) {
      e.printStackTrace();
    }
    Future future3 = mock( Future.class );
    try {
      doReturn( null ).when( future3 ).get();
    } catch ( Exception e ) {
      e.printStackTrace();
    }
    when( service.submit( any( Callable.class ) ) ).thenReturn( future2 ).thenReturn( future3 ).thenReturn( future3 ).thenReturn( future );

    try {
      RepositoryConnectResult res = purRepositoryConnector.connect( "userNam", "password" );
      Assert.assertEquals( "U1", res.getUser().getLogin() );
    } catch ( KettleException e ) {
      e.printStackTrace();
    }
  }