org.pentaho.pac.server.PacServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.pac.server.PacServiceImpl.java

Source

/*
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright 2008 - 2009 Pentaho Corporation.  All rights reserved.
*/
package org.pentaho.pac.server;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.pac.client.PacService;
import org.pentaho.pac.client.utils.ExceptionParser;
import org.pentaho.pac.common.HibernateConfigException;
import org.pentaho.pac.common.PacServiceException;
import org.pentaho.pac.common.PentahoSecurityException;
import org.pentaho.pac.common.ServiceInitializationException;
import org.pentaho.pac.common.UserRoleSecurityInfo;
import org.pentaho.pac.common.UserToRoleAssignment;
import org.pentaho.pac.common.datasources.DataSourceManagementException;
import org.pentaho.pac.common.datasources.DuplicateDataSourceException;
import org.pentaho.pac.common.datasources.NonExistingDataSourceException;
import org.pentaho.pac.common.datasources.PentahoDataSource;
import org.pentaho.pac.common.roles.DuplicateRoleException;
import org.pentaho.pac.common.roles.NonExistingRoleException;
import org.pentaho.pac.common.roles.ProxyPentahoRole;
import org.pentaho.pac.common.users.DuplicateUserException;
import org.pentaho.pac.common.users.NonExistingUserException;
import org.pentaho.pac.common.users.ProxyPentahoUser;
import org.pentaho.pac.server.biplatformproxy.xmlserializer.XActionXmlSerializer;
import org.pentaho.pac.server.biplatformproxy.xmlserializer.XmlSerializerException;
import org.pentaho.pac.server.common.AppConfigProperties;
import org.pentaho.pac.server.common.BiServerTrustedProxy;
import org.pentaho.pac.server.common.DAOException;
import org.pentaho.pac.server.common.HibernateSessionFactory;
import org.pentaho.pac.server.common.PasswordServiceFactory;
import org.pentaho.pac.server.common.ProxyException;
import org.pentaho.pac.server.common.ThreadSafeHttpClient;
import org.pentaho.pac.server.common.ThreadSafeHttpClient.HttpMethodType;
import org.pentaho.pac.server.datasources.DataSourceMgmtService;
import org.pentaho.pac.server.datasources.IDataSourceMgmtService;
import org.pentaho.pac.server.i18n.Messages;
import org.pentaho.platform.api.repository.datasource.IDatasource;
import org.pentaho.platform.api.util.IPasswordService;
import org.pentaho.platform.api.util.PasswordServiceException;
import org.pentaho.platform.engine.security.userroledao.IPentahoRole;
import org.pentaho.platform.engine.security.userroledao.IPentahoUser;
import org.pentaho.platform.engine.security.userroledao.PentahoRole;
import org.pentaho.platform.engine.security.userroledao.PentahoUser;
import org.pentaho.platform.repository.datasource.Datasource;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class PacServiceImpl extends RemoteServiceServlet implements PacService {

    // ~ Static fields/initializers ====================================================================================== 
    private static final String PUBLISH_SERVICE_NAME = "PublishService"; //$NON-NLS-1$
    private static final String SERVICE_ACTION_SERVICE_NAME = "ServiceActionService"; //$NON-NLS-1$
    private static final String RESET_REPOSITORY_SERVICE_NAME = "ResetRepositoryService"; //$NON-NLS-1$
    private static final Log logger = LogFactory.getLog(PacServiceImpl.class);

    private static final long serialVersionUID = 420L;

    private static ThreadSafeHttpClient HTTP_CLIENT = new ThreadSafeHttpClient();

    private static final int DEFAULT_CHECK_PERIOD = 30000; // 30 seconds

    private static BiServerTrustedProxy biServerProxy;

    static {
        biServerProxy = BiServerTrustedProxy.getInstance();
    }

    // ~ Instance fields =================================================================================================

    private IUserRoleMgmtService userRoleMgmtService;

    private IDataSourceMgmtService dataSourceMgmtService;

    // ~ Constructors ====================================================================================================

    public PacServiceImpl() {
        super();
    }

    // ~ Methods =========================================================================================================

    public Boolean isValidConfiguration() throws PacServiceException {
        return AppConfigProperties.getInstance().isValidConfiguration();
    }

    public UserRoleSecurityInfo getUserRoleSecurityInfo() throws PacServiceException {
        UserRoleSecurityInfo userRoleSecurityInfo = new UserRoleSecurityInfo();
        try {
            List<IPentahoUser> users = getUserRoleMgmtService().getUsers();
            for (IPentahoUser user : users) {

                userRoleSecurityInfo.getUsers().add(toProxyUser(user));

                Set<IPentahoRole> roles = user.getRoles();
                for (IPentahoRole role : roles) {
                    userRoleSecurityInfo.getAssignments()
                            .add(new UserToRoleAssignment(user.getUsername(), role.getName()));
                }
            }
            userRoleSecurityInfo.getRoles().addAll(Arrays.asList(getRoles()));

            // add default roles
            List<ProxyPentahoRole> defaultRoles = new ArrayList<ProxyPentahoRole>();
            List<String> defaultRoleStrings = AppConfigProperties.getInstance().getDefaultRoles();
            for (String defaultRoleString : defaultRoleStrings) {
                defaultRoles.add(new ProxyPentahoRole(defaultRoleString));
            }
            userRoleSecurityInfo.getDefaultRoles().addAll(defaultRoles);

        } catch (DAOException e) {
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0033_FAILED_TO_GET_USER_NAME"), //$NON-NLS-1$
                    e);
        }
        return userRoleSecurityInfo;
    }

    // ~ User/Role Methods ===============================================================================================

    public boolean createUser(ProxyPentahoUser proxyUser)
            throws HibernateConfigException, DuplicateUserException, PentahoSecurityException, PacServiceException {
        boolean result = false;

        IPentahoUser user = syncUsers(null, proxyUser);
        try {
            getUserRoleMgmtService().createUser(user);
            result = true;
        } catch (DAOException e) {
            String msg = Messages.getErrorString("PacService.ERROR_0004_USER_CREATION_FAILED", proxyUser.getName()) //$NON-NLS-1$
                    + " " + e.getMessage(); //$NON-NLS-1$
            throw new PacServiceException(msg, e);
        }
        return result;
    }

    public boolean deleteUsers(ProxyPentahoUser[] users) throws HibernateConfigException, NonExistingUserException,
            PentahoSecurityException, PacServiceException {
        boolean result = false;
        IPentahoUser[] persistedUsers;
        try {
            persistedUsers = new IPentahoUser[users.length];
            for (int i = 0; i < users.length; i++) {
                persistedUsers[i] = getUserRoleMgmtService().getUser(users[i].getName());
                if (null == persistedUsers[i]) {
                    throw new NonExistingUserException(users[i].getName());
                }
            }
            for (int i = 0; i < persistedUsers.length; i++) {
                getUserRoleMgmtService().deleteUser(persistedUsers[i]);
            }
            result = true;
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0013_USER_DELETION_FAILED_NO_USER", e.getMessage())); //$NON-NLS-1$
        }
        return result;
    }

    public ProxyPentahoUser getUser(String pUserName) throws HibernateConfigException, PacServiceException {
        ProxyPentahoUser proxyPentahoUser = null;
        try {
            IPentahoUser user = getUserRoleMgmtService().getUser(pUserName);
            if (null != user) {
                proxyPentahoUser = toProxyUser(user);

            }
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0032_FAILED_TO_FIND_USER", pUserName), e); //$NON-NLS-1$
        }
        return proxyPentahoUser;
    }

    public ProxyPentahoUser[] getUsers() throws HibernateConfigException, PacServiceException {
        ProxyPentahoUser[] proxyUsers;
        try {
            List<IPentahoUser> users = getUserRoleMgmtService().getUsers();
            proxyUsers = new ProxyPentahoUser[users.size()];
            int i = 0;
            for (IPentahoUser user : users) {
                proxyUsers[i++] = toProxyUser(user);
            }
        } catch (DAOException e) {
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0033_FAILED_TO_GET_USER_NAME"), //$NON-NLS-1$
                    e);
        }
        return proxyUsers;
    }

    public ProxyPentahoUser[] getUsers(ProxyPentahoRole proxyRole)
            throws HibernateConfigException, NonExistingRoleException, PacServiceException {
        ArrayList<ProxyPentahoUser> users = new ArrayList<ProxyPentahoUser>();
        try {
            IPentahoRole role = getUserRoleMgmtService().getRole(proxyRole.getName());
            if (null != role) {
                for (IPentahoUser user : role.getUsers()) {
                    users.add(toProxyUser(user));
                }
            } else {
                throw new NonExistingRoleException(proxyRole.getName());
            }
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0032_FAILED_TO_FIND_USER", proxyRole.getName()), e); //$NON-NLS-1$
        }
        return users.toArray(new ProxyPentahoUser[0]);
    }

    public boolean updateUser(ProxyPentahoUser proxyUser) throws HibernateConfigException, NonExistingUserException,
            PentahoSecurityException, PacServiceException {
        boolean result = false;
        try {
            IPentahoUser user = getUserRoleMgmtService().getUser(proxyUser.getName());
            if (null == user) {
                throw new NonExistingUserException(proxyUser.getName());
            }
            getUserRoleMgmtService().updateUser(syncUsers(user, proxyUser));
            result = true;
        } catch (DAOException e) {
            String msg = Messages.getErrorString("PacService.ERROR_0038_USER_UPDATE_FAILED", proxyUser.getName()) //$NON-NLS-1$
                    + " " + e.getMessage(); //$NON-NLS-1$
            throw new PacServiceException(msg, e);
        }
        return result;
    }

    public void setRoles(ProxyPentahoUser proxyUser, ProxyPentahoRole[] assignedRoles)
            throws HibernateConfigException, NonExistingRoleException, NonExistingUserException,
            PentahoSecurityException, PacServiceException {
        try {
            IPentahoUser user = getUserRoleMgmtService().getUser(proxyUser.getName());
            if (null == user) {
                throw new NonExistingUserException(proxyUser.getName());
            }

            Set<IPentahoRole> rolesToSet = new HashSet<IPentahoRole>();
            for (ProxyPentahoRole proxyRole : assignedRoles) {
                rolesToSet.add(syncRoles(null, proxyRole));
            }

            user.setRoles(rolesToSet);

            getUserRoleMgmtService().updateUser(user);
        } catch (DAOException e) {
            rollbackTransaction();
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", proxyUser.getName()), e); //$NON-NLS-1$
        }
    }

    public void setUsers(ProxyPentahoRole proxyRole, ProxyPentahoUser[] assignedUsers)
            throws HibernateConfigException, NonExistingRoleException, NonExistingUserException,
            PentahoSecurityException, PacServiceException {
        try {
            IPentahoRole role = getUserRoleMgmtService().getRole(proxyRole.getName());
            if (null == role) {
                throw new NonExistingRoleException(proxyRole.getName());
            }

            Set<IPentahoUser> usersToSet = new HashSet<IPentahoUser>();
            for (ProxyPentahoUser proxyUser : assignedUsers) {
                usersToSet.add(syncUsers(null, proxyUser));
            }

            role.setUsers(usersToSet);

            getUserRoleMgmtService().updateRole(role);
        } catch (DAOException e) {
            rollbackTransaction();
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", proxyRole.getName()), e); //$NON-NLS-1$
        }
    }

    public void updateRole(String roleName, String description, List<String> usernames)
            throws HibernateConfigException, NonExistingRoleException, NonExistingUserException,
            PentahoSecurityException, PacServiceException {
        try {
            IPentahoRole role = getUserRoleMgmtService().getRole(roleName);
            if (null == role) {
                throw new PacServiceException(
                        Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", roleName)); //$NON-NLS-1$
            }

            Set<IPentahoUser> users = new HashSet<IPentahoUser>();
            for (String username : usernames) {
                IPentahoUser user = getUserRoleMgmtService().getUser(username);
                if (null == user) {
                    throw new PacServiceException(
                            Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", roleName)); //$NON-NLS-1$
                }
                users.add(user);
            }

            role.setDescription(description);
            role.setUsers(users);
            getUserRoleMgmtService().updateRole(role);
        } catch (DAOException e) {
            rollbackTransaction();
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", roleName), e); //$NON-NLS-1$
        }
    }

    public boolean createRole(ProxyPentahoRole proxyRole)
            throws HibernateConfigException, DuplicateRoleException, PentahoSecurityException, PacServiceException {
        boolean result = false;
        IPentahoRole role = new PentahoRole(proxyRole.getName());

        try {
            getUserRoleMgmtService().createRole(syncRoles(role, proxyRole));
            result = true;
        } catch (DAOException e) {
            throw new PacServiceException(e);
        }
        return result;
    }

    public boolean deleteRoles(ProxyPentahoRole[] roles) throws HibernateConfigException, NonExistingRoleException,
            PentahoSecurityException, PacServiceException {
        boolean result = false;
        IPentahoRole[] persistedRoles;
        try {
            persistedRoles = new IPentahoRole[roles.length];
            for (int i = 0; i < roles.length; i++) {
                persistedRoles[i] = getUserRoleMgmtService().getRole(roles[i].getName());
                if (null == persistedRoles[i]) {
                    throw new PacServiceException(Messages.getErrorString(
                            "PacService.ERROR_0010_ROLE_DELETION_FAILED_NO_ROLE", roles[i].getName())); //$NON-NLS-1$
                }
            }
            for (int i = 0; i < persistedRoles.length; i++) {
                getUserRoleMgmtService().deleteRole(persistedRoles[i]);
            }
            result = true;
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0011_ROLE_DELETION_FAILED", e.getMessage())); //$NON-NLS-1$
        }
        return result;
    }

    public ProxyPentahoRole[] getRoles(ProxyPentahoUser proxyUser)
            throws HibernateConfigException, NonExistingUserException, PacServiceException {
        List<ProxyPentahoRole> proxyRoles = new ArrayList<ProxyPentahoRole>();
        try {
            IPentahoUser user = getUserRoleMgmtService().getUser(proxyUser.getName());
            if (null != user) {
                for (IPentahoRole role : user.getRoles()) {
                    proxyRoles.add(toProxyRole(role));
                }
            } else {
                throw new NonExistingUserException(proxyUser.getName());
            }
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0032_FAILED_TO_FIND_USER", proxyUser.getName()), e); //$NON-NLS-1$
        }
        return proxyRoles.toArray(new ProxyPentahoRole[0]);
    }

    public ProxyPentahoRole[] getRoles() throws HibernateConfigException, PacServiceException {
        List<ProxyPentahoRole> proxyRoles = new ArrayList<ProxyPentahoRole>();
        try {
            List<IPentahoRole> roles = getUserRoleMgmtService().getRoles();
            for (IPentahoRole role : roles) {
                proxyRoles.add(toProxyRole(role));
            }
        } catch (DAOException e) {
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0031_FAILED_TO_GET_ROLE_NAME"), //$NON-NLS-1$
                    e);
        }
        return proxyRoles.toArray(new ProxyPentahoRole[0]);
    }

    public boolean updateRole(ProxyPentahoRole proxyPentahoRole)
            throws HibernateConfigException, PacServiceException {
        boolean result = false;
        try {
            IPentahoRole role = getUserRoleMgmtService().getRole(proxyPentahoRole.getName());
            if (null == role) {
                throw new PacServiceException(Messages.getErrorString(
                        "PacService.ERROR_0036_ROLE_UPDATE_FAILED_DOES_NOT_EXIST", proxyPentahoRole.getName())); //$NON-NLS-1$
            }

            getUserRoleMgmtService().updateRole(syncRoles(role, proxyPentahoRole));
            result = true;
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0034_ROLE_UPDATE_FAILED", proxyPentahoRole.getName()), //$NON-NLS-1$
                    e);
        } catch (PentahoSecurityException e) {
            throw new PacServiceException(Messages.getErrorString(
                    "PacService.ERROR_0035_ROLE_UPDATE_FAILED_NO_PERMISSION", proxyPentahoRole.getName()), e); //$NON-NLS-1$
        } catch (NonExistingRoleException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0037_ROLE_UPDATE_FAILED_USER_DOES_NOT_EXIST", //$NON-NLS-1$
                            proxyPentahoRole.getName(), /*role name*/e.getMessage()),
                    e);
        }
        return result;
    }

    public boolean createDataSource(PentahoDataSource dataSource)
            throws PacServiceException, HibernateConfigException {
        boolean result = false;
        try {
            getDataSourceMgmtService().beginTransaction();
            // Get the password service
            IPasswordService passwordService = PasswordServiceFactory.getPasswordService();
            // Store the new encrypted password in the datasource object
            String encryptedPassword = passwordService.encrypt(dataSource.getPassword());
            dataSource.setPassword(encryptedPassword);
            getDataSourceMgmtService().createDataSource(toDatasource(dataSource));
            getDataSourceMgmtService().commitTransaction();
            result = true;
        } catch (PasswordServiceException pse) {
            throw new PacServiceException(pse.getMessage(), pse);
        } catch (DuplicateDataSourceException dde) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0009_DATASOURCE_ALREADY_EXIST", dataSource.getName()), //$NON-NLS-1$
                    dde);

        } catch (DAOException e) {
            throw new PacServiceException(Messages
                    .getErrorString("PacService.ERROR_0007_DATASOURCE_CREATION_FAILED", dataSource.getName()), e); //$NON-NLS-1$
        } catch (PentahoSecurityException pse) {
            throw new PacServiceException(Messages.getErrorString(
                    "PacService.ERROR_0008_NO_CREATE_DATASOURCE_PERMISSION", dataSource.getName()), pse); //$NON-NLS-1$

        } finally {
            if (!result) {
                rollbackTransaction();
            }
            getDataSourceMgmtService().closeSession();
        }
        return result;

    }

    public boolean deleteDataSources(PentahoDataSource[] dataSources)
            throws HibernateConfigException, PacServiceException {
        boolean result = false;
        IDatasource persistedDatasource = null;
        try {
            getDataSourceMgmtService().beginTransaction();
            for (int i = 0; i < dataSources.length; i++) {
                persistedDatasource = getDataSourceMgmtService().getDataSource(dataSources[i].getName());
                getDataSourceMgmtService().deleteDataSource(persistedDatasource);
            }
            result = true;
            getDataSourceMgmtService().commitTransaction();
        } catch (NonExistingDataSourceException neds) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0016_DATASOURCE_DELETION_FAILED_NO_DATASOURCE", //$NON-NLS-1$
                            persistedDatasource.getName(), neds.getMessage()),
                    neds);
        } catch (DAOException e) {
            throw new PacServiceException(Messages.getErrorString(
                    "PacService.ERROR_0017_DATASOURCE_DELETION_FAILED", persistedDatasource.getName()), e); //$NON-NLS-1$
        } catch (PentahoSecurityException pse) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0018_DATASOURCE_DELETION_FAILED_NO_PERMISSION", //$NON-NLS-1$
                            persistedDatasource.getName()),
                    pse);
        } finally {
            if (!result) {
                rollbackTransaction();
            }
            getDataSourceMgmtService().closeSession();
        }
        return result;
    }

    public boolean updateDataSource(PentahoDataSource dataSource)
            throws HibernateConfigException, PacServiceException {
        boolean result = false;
        try {
            IDatasource ds = getDataSourceMgmtService().getDataSource(dataSource.getName());
            if (null == ds) {
                throw new NonExistingDataSourceException(dataSource.getName());
            }
            ds.setDriverClass(dataSource.getDriverClass());
            if (dataSource.getIdleConn() < 0) {
                ds.setIdleConn(0);
            } else {
                ds.setIdleConn(dataSource.getIdleConn());
            }
            if (dataSource.getMaxActConn() < 0) {
                ds.setMaxActConn(0);
            } else {
                ds.setMaxActConn(dataSource.getMaxActConn());
            }

            IPasswordService passwordService = PasswordServiceFactory.getPasswordService();
            // Store the new encrypted password in the datasource object
            ds.setPassword(passwordService.encrypt(dataSource.getPassword()));
            ds.setQuery(dataSource.getQuery());
            ds.setUrl(dataSource.getUrl());
            ds.setUserName(dataSource.getUserName());
            if (dataSource.getMaxActConn() < 0) {
                ds.setWait(0);
            } else {
                ds.setWait(dataSource.getWait());
            }

            getDataSourceMgmtService().beginTransaction();
            getDataSourceMgmtService().updateDataSource(ds);
            getDataSourceMgmtService().commitTransaction();
            result = true;
        } catch (PasswordServiceException pse) {
            throw new PacServiceException(pse.getMessage(), pse);
        } catch (NonExistingDataSourceException neds) {
            throw new PacServiceException(Messages.getErrorString(
                    "PacService.ERROR_0021_DATASOURCE_UPDATE_FAILED_DOES_NOT_EXIST", dataSource.getName()), neds); //$NON-NLS-1$
        } catch (DAOException e) {
            throw new PacServiceException(
                    Messages.getErrorString("PacService.ERROR_0019_DATASOURCE_UPDATE_FAILED", dataSource.getName()), //$NON-NLS-1$
                    e);
        } catch (PentahoSecurityException pse) {
            throw new PacServiceException(Messages.getErrorString(
                    "PacService.ERROR_0020_DATASOURCE_UPDATE_FAILED_NO_PERMISSION", dataSource.getName()), pse); //$NON-NLS-1$

        } finally {
            if (!result) {
                rollbackTransaction();
            }
            getDataSourceMgmtService().closeSession();
        }
        return result;
    }

    public PentahoDataSource[] getDataSources() throws HibernateConfigException, PacServiceException {
        List<IDatasource> datasources;
        PentahoDataSource[] pentahoDataSources;
        try {
            datasources = getDataSourceMgmtService().getDataSources();
            pentahoDataSources = new PentahoDataSource[datasources.size()];
            int i = 0;
            for (IDatasource datasource : datasources) {
                try {
                    // Get the password service
                    if (datasource != null) {
                        IPasswordService passwordService = PasswordServiceFactory.getPasswordService();
                        String decryptedPassword = passwordService.decrypt(datasource.getPassword());
                        datasource.setPassword(decryptedPassword);
                        pentahoDataSources[i++] = toPentahoDataSource(datasource);
                    }
                } catch (PasswordServiceException pse) {
                    throw new DAOException(pse.getMessage(), pse);
                }
            }
        } catch (DAOException e) {
            // TODO need a way better error message here please, maybe include some information from the exception?
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0023_FAILED_TO_GET_DATASDOURCE", //$NON-NLS-1$
                    e.getLocalizedMessage()), e);
        } finally {
            if (dataSourceMgmtService != null) {
                getDataSourceMgmtService().closeSession();
            }
        }
        return pentahoDataSources;
    }

    /**
     * NOTE: caller is responsible for closing connection
     * 
     * @param ds
     * @return
     * @throws DataSourceManagementException
     */
    private static Connection getDataSourceConnection(PentahoDataSource ds) throws DataSourceManagementException {
        Connection conn = null;

        String driverClass = ds.getDriverClass();
        if (StringUtils.isEmpty(driverClass)) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0024_CONNECTION_ATTEMPT_FAILED", driverClass)); //$NON-NLS-1$  
        }
        Class<?> driverC = null;

        try {
            driverC = Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0026_DRIVER_NOT_FOUND_IN_CLASSPATH", driverClass), e); //$NON-NLS-1$
        }
        if (!Driver.class.isAssignableFrom(driverC)) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0026_DRIVER_NOT_FOUND_IN_CLASSPATH", driverClass)); //$NON-NLS-1$    }
        }
        Driver driver = null;

        try {
            driver = driverC.asSubclass(Driver.class).newInstance();
        } catch (InstantiationException e) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0027_UNABLE_TO_INSTANCE_DRIVER", driverClass), e); //$NON-NLS-1$
        } catch (IllegalAccessException e) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0027_UNABLE_TO_INSTANCE_DRIVER", driverClass), e); //$NON-NLS-1$    }
        }
        try {
            DriverManager.registerDriver(driver);
            conn = DriverManager.getConnection(ds.getUrl(), ds.getUserName(), ds.getPassword());
            return conn;
        } catch (SQLException e) {
            throw new DataSourceManagementException(
                    Messages.getErrorString("PacService.ERROR_0025_UNABLE_TO_CONNECT", e.getMessage()), e); //$NON-NLS-1$
        }
    }

    public boolean testDataSourceConnection(PentahoDataSource ds) throws PacServiceException {
        Connection conn = null;
        try {
            conn = getDataSourceConnection(ds);
        } catch (DataSourceManagementException dme) {
            throw new PacServiceException(dme.getMessage(), dme);
        } finally {
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                throw new PacServiceException(e);
            }
        }
        return true;
    }

    public boolean testDataSourceValidationQuery(PentahoDataSource ds) throws PacServiceException {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = getDataSourceConnection(ds);

            if (!StringUtils.isEmpty(ds.getQuery())) {
                stmt = conn.createStatement();
                rs = stmt.executeQuery(ds.getQuery());
            } else {
                throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0028_QUERY_NOT_VALID")); //$NON-NLS-1$
            }
        } catch (DataSourceManagementException dme) {
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0029_QUERY_VALIDATION_FAILED", //$NON-NLS-1$
                    dme.getLocalizedMessage()), dme);
        } catch (SQLException e) {
            throw new PacServiceException(Messages.getErrorString("PacService.ERROR_0029_QUERY_VALIDATION_FAILED", //$NON-NLS-1$
                    e.getLocalizedMessage()), e);
        } finally {
            try {
                closeAll(conn, stmt, rs, true);
            } catch (SQLException e) {
                throw new PacServiceException(e);
            }
        }
        return true;
    }

    private void rollbackTransaction() {
        try {
            getDataSourceMgmtService().rollbackTransaction();
        } catch (Exception e) {
            logger.error(Messages.getErrorString("PacService.ERROR_0048_ROLLBACK_FAILED")); //$NON-NLS-1$
        }
    }

    public String refreshSolutionRepository() throws PacServiceException {
        return executePublishRequest("org.pentaho.platform.engine.services.solution.SolutionPublisher"); //$NON-NLS-1$
    }

    public String cleanRepository() throws PacServiceException {
        return executeXAction("admin", "", "clean_repository.xaction"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }

    public String clearMondrianSchemaCache() throws PacServiceException {
        return executeXAction("admin", "", "clear_mondrian_schema_cache.xaction"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }

    public String scheduleRepositoryCleaning() throws PacServiceException {
        return executeXAction("admin", "", "schedule-clean.xaction"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }

    public String resetRepository() throws PacServiceException {
        return resetSolutionRepository(getUserName());
    }

    public String refreshSystemSettings() throws PacServiceException {
        return executePublishRequest("org.pentaho.platform.engine.core.system.SettingsPublisher"); //$NON-NLS-1$
    }

    public String executeGlobalActions() throws PacServiceException {
        return executePublishRequest("org.pentaho.platform.engine.core.system.GlobalListsPublisher"); //$NON-NLS-1$
    }

    public String refreshReportingMetadata() throws PacServiceException {
        return executePublishRequest("org.pentaho.platform.engine.services.metadata.MetadataPublisher"); //$NON-NLS-1$
    }

    public String getUserName() {
        return StringUtils.defaultIfEmpty(AppConfigProperties.getInstance().getPlatformUsername(),
                System.getProperty(AppConfigProperties.KEY_PLATFORM_USERNAME));
    }

    public String getPciContextPath() throws PacServiceException {
        return StringUtils.defaultIfEmpty(AppConfigProperties.getInstance().getBiServerContextPath(),
                System.getProperty(AppConfigProperties.KEY_BISERVER_CONTEXT_PATH));
    }

    public String getBIServerBaseUrl() {
        return StringUtils.defaultIfEmpty(AppConfigProperties.getInstance().getBiServerBaseUrl(),
                System.getProperty(AppConfigProperties.KEY_BISERVER_BASE_URL));
    }

    private String executeXAction(String solution, String path, String xAction) throws PacServiceException {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("solution", solution); //$NON-NLS-1$
        params.put("path", path); //$NON-NLS-1$
        params.put("action", xAction); //$NON-NLS-1$

        String strResponse;
        try {
            strResponse = biServerProxy.execRemoteMethod(getBIServerBaseUrl(), SERVICE_ACTION_SERVICE_NAME,
                    HttpMethodType.GET, getUserName(), params);
        } catch (ProxyException e) {
            throw new PacServiceException(ExceptionParser.getErrorMessage(e.getMessage(), e.getMessage()), e);
        }
        XActionXmlSerializer s = new XActionXmlSerializer();
        String errorMsg;
        try {
            errorMsg = s.getXActionResponseStatusFromXml(strResponse);
        } catch (XmlSerializerException e) {
            throw new PacServiceException(e.getMessage(), e);
        }
        if (null != errorMsg) {
            throw new PacServiceException(errorMsg);
        }

        return Messages.getString("PacService.ACTION_COMPLETE"); //$NON-NLS-1$
    }

    private String executePublishRequest(String publisherClassName) throws PacServiceException {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("publish", "now"); //$NON-NLS-1$ //$NON-NLS-2$
        params.put("style", "popup"); //$NON-NLS-1$ //$NON-NLS-2$
        params.put("class", publisherClassName); //$NON-NLS-1$

        String strResponse;
        try {
            strResponse = biServerProxy.execRemoteMethod(getBIServerBaseUrl(), PUBLISH_SERVICE_NAME,
                    HttpMethodType.GET, getUserName(), params);
        } catch (ProxyException e) {
            throw new PacServiceException(ExceptionParser.getErrorMessage(e.getMessage(), e.getMessage()), e);
        }
        XActionXmlSerializer s = new XActionXmlSerializer();
        String errorMsg = s.getPublishStatusFromXml(strResponse);
        if (null != errorMsg) {
            throw new PacServiceException(errorMsg);
        }

        return Messages.getString("PacService.ACTION_COMPLETE");//$NON-NLS-1$
    }

    private String resetSolutionRepository(String userid) throws PacServiceException {

        try {
            biServerProxy.execRemoteMethod(getBIServerBaseUrl(), RESET_REPOSITORY_SERVICE_NAME, HttpMethodType.GET,
                    getUserName(), /*params*/null);
        } catch (ProxyException e) {
            throw new PacServiceException(ExceptionParser.getErrorMessage(e.getMessage(), e.getMessage()), e);
        }
        return Messages.getString("PacService.ACTION_COMPLETE"); //$NON-NLS-1$
    }

    public String getHomepageUrl() {
        return AppConfigProperties.getInstance().getHomepageUrl();
    }

    public String getHomePageAsHtml(String url) {

        String html = null;
        HttpClient client = new HttpClient();
        GetMethod get = null;
        try {

            String timeOut = AppConfigProperties.getInstance().getHomepageTimeout();
            HttpMethodParams params = new HttpMethodParams();
            params.setParameter(HttpMethodParams.SO_TIMEOUT, Integer.parseInt(timeOut));
            get = new GetMethod(url);
            get.setParams(params);
            client.executeMethod(get);

            //getResponseBodyAsString() and the like were decoding as ISO-8859-1 instead of UTF-8.
            //This is indeed the default behavior of HttpClient if the charset is not defined in 
            //the Content-Type reponse header. We're overriding that since we know our source is
            //UTF-8
            byte[] bytes = get.getResponseBody();
            html = new String(bytes, "UTF-8"); //$NON-NLS-1$

        } catch (Exception e) {
            logger.error(e);
            html = showStatic();
        } finally {
            if (get != null) {
                get.releaseConnection();
            }
        }
        final String BODY_TAG = "<body>"; //$NON-NLS-1$

        int afterBodyIdx = html.indexOf(BODY_TAG);
        if (-1 != afterBodyIdx) {
            html = html.substring(html.indexOf(BODY_TAG) + BODY_TAG.length());
            html = html.substring(0, html.indexOf("</body>")); //$NON-NLS-1$
        }

        return html;
    }

    private String showStatic() {
        String templateFileName = "defaultHome.ftl"; //$NON-NLS-1$
        InputStream flatFile = getClass().getResourceAsStream(templateFileName);
        try {
            return IOUtils.toString(flatFile);
        } catch (IOException e) {
            String msg = Messages.getErrorString("PacService.ERROR_0047_IO_ERROR", templateFileName); //$NON-NLS-1$
            logger.error(msg, e);
            return "<span>" + msg + "</span>"; //$NON-NLS-1$ //$NON-NLS-2$
        }
    }

    public void isBiServerAlive() throws PacServiceException {
        try {
            HTTP_CLIENT.execRemoteMethod(getBIServerBaseUrl(), "ping/alive.gif", HttpMethodType.GET, null);//$NON-NLS-1$
        } catch (Exception e) {
            throw new PacServiceException(e.getMessage(), e);
        }
    }

    public int getBiServerStatusCheckPeriod() {
        String strBiServerStatusCheckPeriod = StringUtils.defaultIfEmpty(
                AppConfigProperties.getInstance().getBiServerStatusCheckPeriod(),
                System.getProperty(AppConfigProperties.KEY_BISERVER_STATUS_CHECK_PERIOD));
        try {
            if (strBiServerStatusCheckPeriod != null && strBiServerStatusCheckPeriod.length() > 0) {
                return Integer.parseInt(strBiServerStatusCheckPeriod);
            } else {
                return DEFAULT_CHECK_PERIOD;
            }
        } catch (NumberFormatException e) {
            logger.error(Messages.getErrorString("PacService.ERROR_0045_THREAD_SCHEDULING_FAILED"), e); //$NON-NLS-1$
            return DEFAULT_CHECK_PERIOD;
        }
    }

    public void initialze() throws ServiceInitializationException {
    }

    private IUserRoleMgmtService getUserRoleMgmtService() throws HibernateConfigException {
        if (userRoleMgmtService == null) {
            synchronized (this) {
                if (userRoleMgmtService == null) {
                    refreshHibernateConfig();
                }
            }
        }
        return userRoleMgmtService;
    }

    private IDataSourceMgmtService getDataSourceMgmtService() throws HibernateConfigException {
        if (dataSourceMgmtService == null) {
            synchronized (this) {
                if (dataSourceMgmtService == null) {
                    refreshHibernateConfig();
                }
            }
        }
        return dataSourceMgmtService;
    }

    public synchronized void refreshHibernateConfig() throws HibernateConfigException {
        try {
            HibernateSessionFactory.initDefaultConfiguration();
            userRoleMgmtService = new UserRoleMgmtService();
            dataSourceMgmtService = new DataSourceMgmtService();
        } catch (Exception e) {
            throw new HibernateConfigException(
                    Messages.getString("PacService.ERROR_0062_UNABLE_TO_REFRESH_HIBERNATE"), e); //$NON-NLS-1$      
        }
    }

    public String getHelpUrl() {
        return AppConfigProperties.getInstance().getHelpUrl();
    }

    //~ User/Role Support Methods ========================================================================================

    protected ProxyPentahoUser toProxyUser(IPentahoUser user) throws PacServiceException {
        ProxyPentahoUser proxyPentahoUser = new ProxyPentahoUser();
        proxyPentahoUser.setName(user.getUsername());
        proxyPentahoUser.setDescription(user.getDescription());
        proxyPentahoUser.setEnabled(user.isEnabled());
        proxyPentahoUser.setPassword(""); //$NON-NLS-1$
        return proxyPentahoUser;
    }

    /**
     * Synchronizes <code>user</code> with fields from <code>proxyUser</code>. The roles set of given <code>user</code> is
     * unmodified.
     */
    protected IPentahoUser syncUsers(IPentahoUser user, ProxyPentahoUser proxyUser) throws PacServiceException {
        IPentahoUser syncedUser = user;
        if (syncedUser == null) {
            syncedUser = new PentahoUser(proxyUser.getName());
        }
        syncedUser.setDescription(proxyUser.getDescription());

        // PPP-1527: Password is never sent back to the UI. It always shows as blank. If the user leaves it blank,
        // password is not changed. If the user enters a value, set the password.
        if (!StringUtils.isBlank(proxyUser.getPassword())) {
            syncedUser.setPassword(AppConfigProperties.getInstance().getPasswordEncoder()
                    .encodePassword(proxyUser.getPassword(), null));
        }
        syncedUser.setEnabled(proxyUser.getEnabled());
        return syncedUser;
    }

    /**
     * Synchronizes <code>role</code> with fields from <code>proxyRole</code>. The users set of given <code>role</code> is
     * unmodified.
     */
    protected IPentahoRole syncRoles(IPentahoRole role, ProxyPentahoRole proxyRole) throws PacServiceException {
        IPentahoRole syncedRole = role;
        if (syncedRole == null) {
            syncedRole = new PentahoRole(proxyRole.getName());
        }
        syncedRole.setDescription(proxyRole.getDescription());
        return syncedRole;
    }

    protected ProxyPentahoRole toProxyRole(IPentahoRole role) throws PacServiceException {
        ProxyPentahoRole proxyRole = new ProxyPentahoRole(role.getName());
        proxyRole.setDescription(role.getDescription());
        return proxyRole;
    }

    protected PentahoDataSource toPentahoDataSource(IDatasource datasource) throws PacServiceException {
        PentahoDataSource pentahoDataSource = new PentahoDataSource();
        pentahoDataSource.setDriverClass(datasource.getDriverClass());
        pentahoDataSource.setIdleConn(datasource.getIdleConn());
        pentahoDataSource.setMaxActConn(datasource.getMaxActConn());
        pentahoDataSource.setName(datasource.getName());
        pentahoDataSource.setPassword(datasource.getPassword());
        pentahoDataSource.setQuery(datasource.getQuery());
        pentahoDataSource.setUrl(datasource.getUrl());
        pentahoDataSource.setUserName(datasource.getUserName());
        pentahoDataSource.setWait(datasource.getWait());
        return pentahoDataSource;
    }

    protected IDatasource toDatasource(PentahoDataSource pentahoDataSource) throws PacServiceException {
        IDatasource datasource = new Datasource();

        datasource.setDriverClass(pentahoDataSource.getDriverClass());
        datasource.setIdleConn(pentahoDataSource.getIdleConn());
        datasource.setMaxActConn(pentahoDataSource.getMaxActConn());
        datasource.setName(pentahoDataSource.getName());
        datasource.setPassword(pentahoDataSource.getPassword());
        datasource.setQuery(pentahoDataSource.getQuery());
        datasource.setUrl(pentahoDataSource.getUrl());
        datasource.setUserName(pentahoDataSource.getUserName());
        datasource.setWait(pentahoDataSource.getWait());
        return datasource;

    }

    private void closeAll(Connection conn, Statement stmt, ResultSet rs, boolean throwsException)
            throws SQLException {
        SQLException rethrow = null;
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ignored) {
                rethrow = ignored;
            }
            rs = null;
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException ignored) {
                rethrow = ignored;
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException ignored) {
                rethrow = ignored;
            }
            conn = null;
        }
        if (throwsException && rethrow != null) {
            throw rethrow;
        }

    }

}