org.pentaho.di.repository.pur.PurRepositoryConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.repository.pur.PurRepositoryConnector.java

Source

/*!
 * Copyright 2010 - 2017 Pentaho Corporation.  All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.pentaho.di.repository.pur;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import javax.xml.ws.WebServiceException;

import org.apache.commons.lang.BooleanUtils;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleSecurityException;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.util.ExecutorUtil;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.IUser;
import org.pentaho.di.repository.RepositorySecurityManager;
import org.pentaho.di.repository.RepositorySecurityProvider;
import org.pentaho.di.repository.pur.model.EEUserInfo;
import org.pentaho.di.ui.repository.pur.services.IAbsSecurityManager;
import org.pentaho.di.ui.repository.pur.services.IAbsSecurityProvider;
import org.pentaho.di.ui.repository.pur.services.IAclService;
import org.pentaho.di.ui.repository.pur.services.IConnectionAclService;
import org.pentaho.di.ui.repository.pur.services.ILockService;
import org.pentaho.di.ui.repository.pur.services.IRevisionService;
import org.pentaho.di.ui.repository.pur.services.IRoleSupportSecurityManager;
import org.pentaho.di.ui.repository.pur.services.ITrashService;
import org.pentaho.platform.api.repository2.unified.IUnifiedRepository;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository2.unified.webservices.jaxws.IUnifiedRepositoryJaxwsWebService;
import org.pentaho.platform.repository2.unified.webservices.jaxws.UnifiedRepositoryToWebServiceAdapter;

import com.pentaho.pdi.ws.IRepositorySyncWebService;
import com.pentaho.pdi.ws.RepositorySyncException;
import com.sun.xml.ws.client.ClientTransportException;

public class PurRepositoryConnector implements IRepositoryConnector {
    private static final String SINGLE_DI_SERVER_INSTANCE = "singleDiServerInstance";
    private static final String REMOTE_DI_SERVER_INSTANCE = "remoteDiServerInstance";
    private static Class<?> PKG = PurRepository.class;
    private final LogChannelInterface log;
    private final PurRepository purRepository;
    private final PurRepositoryMeta repositoryMeta;
    private final RootRef rootRef;
    private ServiceManager serviceManager;

    public PurRepositoryConnector(PurRepository purRepository, PurRepositoryMeta repositoryMeta, RootRef rootRef) {
        log = new LogChannel(this.getClass().getSimpleName());
        if (purRepository != null & purRepository.getLog() != null) {
            log.setLogLevel(purRepository.getLog().getLogLevel());
        }
        this.purRepository = purRepository;
        this.repositoryMeta = repositoryMeta;
        this.rootRef = rootRef;
    }

    private boolean allowedActionsContains(AbsSecurityProvider provider, String action) throws KettleException {
        List<String> allowedActions = provider.getAllowedActions(IAbsSecurityProvider.NAMESPACE);
        for (String actionName : allowedActions) {
            if (action != null && action.equals(actionName)) {
                return true;
            }
        }
        return false;
    }

    public synchronized RepositoryConnectResult connect(final String username, final String password)
            throws KettleException, KettleSecurityException {
        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 {
            /*
             * 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(decryptedPassword);
            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("begin connectInProcess()");
                        }
                        String name = PentahoSessionHolder.getSession().getName();
                        user1 = new EEUserInfo();
                        user1.setLogin(name);
                        user1.setName(name);
                        user1.setPassword(decryptedPassword);
                        result.setUser(user1);
                        result.setSuccess(true);

                        if (log.isDebug()) {
                            log.logDebug("connected in process as '" + name + "' pur repository = "
                                    + result.getUnifiedRepository());
                        }

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

            ExecutorService executor = ExecutorUtil.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, decryptedPassword,
                                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,
                                decryptedPassword, 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 (ClientTransportException e) {
                        // caused by authentication errors, etc
                        return e;
                    } 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;
                }
            });

            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();

            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, decryptedPassword,
                            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 npe) {
            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;
    }

    @Override
    public synchronized void disconnect() {
        if (serviceManager != null) {
            serviceManager.close();
        }
        serviceManager = null;
    }

    public LogChannelInterface getLog() {
        return log;
    }

    @Override
    public ServiceManager getServiceManager() {
        return serviceManager;
    }

    public static boolean inProcess() {
        boolean inProcess = false;
        boolean remoteDiServer = BooleanUtils
                .toBoolean(PentahoSystem.getSystemSetting(REMOTE_DI_SERVER_INSTANCE, "false")); //$NON-NLS-1$
        if ("true".equals(PentahoSystem.getSystemSetting(SINGLE_DI_SERVER_INSTANCE, "true"))) { //$NON-NLS-1$ //$NON-NLS-2$
            inProcess = true;
        } else if (!remoteDiServer && PentahoSystem.getApplicationContext().getFullyQualifiedServerURL() != null) {
            inProcess = true;
        }
        return inProcess;
    }
}