Java tutorial
/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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.ui.repo; import org.apache.commons.lang.ClassUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.KettleLogStore; import org.pentaho.di.core.logging.LogChannelInterface; import org.pentaho.di.core.plugins.PluginInterface; import org.pentaho.di.core.plugins.PluginRegistry; import org.pentaho.di.core.plugins.RepositoryPluginType; import org.pentaho.di.core.util.ExecutorUtil; import org.pentaho.di.repository.AbstractRepository; import org.pentaho.di.repository.ReconnectableRepository; import org.pentaho.di.repository.RepositoriesMeta; import org.pentaho.di.repository.Repository; import org.pentaho.di.repository.RepositoryMeta; import org.pentaho.di.trans.Trans; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.repo.model.RepositoryModel; import org.pentaho.di.ui.spoon.Spoon; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.function.Supplier; /** * Created by bmorrise on 4/18/16. */ public class RepositoryConnectController { public static final String DISPLAY_NAME = "displayName"; public static final String DESCRIPTION = "description"; public static final String IS_DEFAULT = "isDefault"; public static final String URL = "url"; public static final String DATABASE_CONNECTION = "databaseConnection"; public static final String SHOW_HIDDEN_FOLDERS = "showHiddenFolders"; public static final String LOCATION = "location"; public static final String DO_NOT_MODIFY = "doNotModify"; public static final String DEFAULT_URL = "defaultUrl"; public static final String ERROR_401 = "401"; private static Class<?> PKG = RepositoryConnectController.class; private static LogChannelInterface log = KettleLogStore.getLogChannelInterfaceFactory() .create(RepositoryConnectController.class); private RepositoryMeta currentRepository; private RepositoryMeta connectedRepository; private RepositoriesMeta repositoriesMeta; private PluginRegistry pluginRegistry; private Supplier<Spoon> spoonSupplier; private List<RepositoryContollerListener> listeners = new ArrayList<>(); private boolean relogin = false; public RepositoryConnectController(PluginRegistry pluginRegistry, Supplier<Spoon> spoonSupplier, RepositoriesMeta repositoriesMeta) { this.pluginRegistry = pluginRegistry; this.spoonSupplier = spoonSupplier; this.repositoriesMeta = repositoriesMeta; try { repositoriesMeta.readData(); } catch (KettleException ke) { log.logError("Unable to load repositories", ke); } } public RepositoryConnectController() { this(PluginRegistry.getInstance(), Spoon::getInstance, new RepositoriesMeta()); } @SuppressWarnings("unchecked") public String getPlugins() { List<PluginInterface> plugins = pluginRegistry.getPlugins(RepositoryPluginType.class); JSONArray list = new JSONArray(); for (PluginInterface pluginInterface : plugins) { if (!pluginInterface.getIds()[0].equals("PentahoEnterpriseRepository")) { JSONObject repoJSON = new JSONObject(); repoJSON.put("id", pluginInterface.getIds()[0]); repoJSON.put("name", pluginInterface.getName()); repoJSON.put("description", pluginInterface.getDescription()); list.add(repoJSON); } } return list.toString(); } public boolean createRepository(String id, Map<String, Object> items) { try { RepositoryMeta repositoryMeta = pluginRegistry.loadClass(RepositoryPluginType.class, id, RepositoryMeta.class); repositoryMeta.populate(items, repositoriesMeta); if (repositoryMeta.getName() != null) { Repository repository = pluginRegistry.loadClass(RepositoryPluginType.class, repositoryMeta.getId(), Repository.class); repository.init(repositoryMeta); if (currentRepository != null) { if (isCompatibleRepositoryEdit(repositoryMeta)) { setConnectedRepository(repositoryMeta); } repositoriesMeta.removeRepository(repositoriesMeta.indexOfRepository(currentRepository)); } repositoriesMeta.addRepository(repositoryMeta); repositoriesMeta.writeData(); currentRepository = repositoryMeta; if (!testRepository(repository)) { return false; } ((AbstractRepository) repository).create(); } } catch (KettleException ke) { log.logError("Unable to load repository type", ke); return false; } return true; } private boolean isCompatibleRepositoryEdit(RepositoryMeta repositoryMeta) { if (repositoriesMeta.indexOfRepository(currentRepository) >= 0 && connectedRepository != null && repositoryEquals(connectedRepository, currentRepository)) { // only name / description / default changed ? RepositoryMeta clone = repositoryMeta.clone(); clone.setName(connectedRepository.getName()); clone.setDescription(connectedRepository.getDescription()); clone.setDefault(connectedRepository.isDefault()); return repositoryEquals(connectedRepository, clone); } return false; } private boolean repositoryEquals(RepositoryMeta repo1, RepositoryMeta repo2) { return repo1.toJSONObject().equals(repo2.toJSONObject()); } @SuppressWarnings("unchecked") public String getRepositories() { JSONArray list = new JSONArray(); if (repositoriesMeta != null) { for (int i = 0; i < repositoriesMeta.nrRepositories(); i++) { list.add(repositoriesMeta.getRepository(i).toJSONObject()); } } return list.toString(); } public String getRepository(String name) { RepositoryMeta repositoryMeta = repositoriesMeta.findRepository(name); if (repositoryMeta != null) { currentRepository = repositoryMeta; return repositoryMeta.toJSONObject().toString(); } return ""; } public DatabaseMeta getDatabase(String name) { return repositoriesMeta.searchDatabase(name); } public void removeDatabase(String name) { int index = repositoriesMeta.indexOfDatabase(repositoriesMeta.searchDatabase(name)); if (index != -1) { repositoriesMeta.removeDatabase(index); } save(); } @SuppressWarnings("unchecked") public String getDatabases() { JSONArray list = new JSONArray(); for (int i = 0; i < repositoriesMeta.nrDatabases(); i++) { JSONObject databaseJSON = new JSONObject(); databaseJSON.put("name", repositoriesMeta.getDatabase(i).getName()); list.add(databaseJSON); } return list.toString(); } public void connectToRepository() throws KettleException { connectToRepository(currentRepository); } public void connectToRepository(String username, String password) throws KettleException { connectToRepository(currentRepository, username, password); } public void connectToRepository(RepositoryMeta repositoryMeta) throws KettleException { connectToRepository(repositoryMeta, null, null); } public void connectToRepository(RepositoryMeta repositoryMeta, String username, String password) throws KettleException { final Repository repository = loadRepositoryObject(repositoryMeta.getId()); repository.init(repositoryMeta); repositoryConnect(repository, username, password); if (username != null) { getPropsUI().setLastRepositoryLogin(username); } Spoon spoon = spoonSupplier.get(); Runnable execute = () -> { if (spoon.getRepository() != null) { spoon.closeRepository(); } else { spoon.closeAllJobsAndTransformations(true); } spoon.setRepository(repository); setConnectedRepository(repositoryMeta); fireListeners(); }; if (spoon.getShell() != null) { spoon.getShell().getDisplay().asyncExec(execute); } else { execute.run(); } } private Repository loadRepositoryObject(String id) throws KettleException { Repository repository = pluginRegistry.loadClass(RepositoryPluginType.class, id, Repository.class); if (repository instanceof ReconnectableRepository) { repository = wrapWithRepositoryTimeoutHandler((ReconnectableRepository) repository); } return repository; } public void reconnectToRepository(String username, String password) throws KettleException { Repository currentRepositoryInstance = getConnectedRepositoryInstance(); reconnectToRepository(currentRepository, (ReconnectableRepository) currentRepositoryInstance, username, password); } private void reconnectToRepository(RepositoryMeta repositoryMeta, ReconnectableRepository repository, String username, String password) throws KettleException { if (username != null) { getPropsUI().setLastRepositoryLogin(username); } if (repository.isConnected()) { repository.disconnect(); } repository.init(repositoryMeta); repositoryConnect(repository, username, password); } private void repositoryConnect(Repository repository, String username, String password) throws KettleException { ExecutorService executorService = ExecutorUtil.getExecutor(); Future<KettleException> future = executorService.submit(() -> { ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(Trans.class.getClassLoader()); repository.connect(username, password); } catch (KettleException e) { return e; } finally { Thread.currentThread().setContextClassLoader(currentClassLoader); } return null; }); try { KettleException exception = future.get(); if (exception != null) { throw exception; } } catch (InterruptedException | ExecutionException e) { throw new KettleException(); } } private boolean testRepository(Repository repository) { ExecutorService executorService = ExecutorUtil.getExecutor(); Future<Boolean> future = executorService.submit(() -> { ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(Trans.class.getClassLoader()); return ((AbstractRepository) repository).test(); } finally { Thread.currentThread().setContextClassLoader(currentClassLoader); } }); try { return future.get(); } catch (InterruptedException | ExecutionException e) { return false; } } public boolean deleteRepository(String name) { RepositoryMeta repositoryMeta = repositoriesMeta.findRepository(name); int index = repositoriesMeta.indexOfRepository(repositoryMeta); if (index != -1) { Spoon spoon = spoonSupplier.get(); if (spoon.getRepositoryName() != null && spoon.getRepositoryName().equals(repositoryMeta.getName())) { spoon.closeRepository(); setConnectedRepository(null); } repositoriesMeta.removeRepository(index); save(); } return true; } public void addDatabase(DatabaseMeta databaseMeta) { if (databaseMeta != null) { repositoriesMeta.addDatabase(databaseMeta); save(); } } public boolean setDefaultRepository(String name) { RepositoryMeta repositoryMeta = repositoriesMeta.findRepository(name); for (int i = 0; i < repositoriesMeta.nrRepositories(); i++) { repositoriesMeta.getRepository(i).setDefault(false); } if (repositoryMeta != null) { repositoryMeta.setDefault(true); } try { repositoriesMeta.writeData(); } catch (KettleException ke) { log.logError("Unable to set default repository", ke); } return true; } public String getDefaultUrl() { ResourceBundle resourceBundle = PropertyResourceBundle.getBundle(PKG.getPackage().getName() + ".plugin"); return resourceBundle.getString(DEFAULT_URL); } public String getCurrentUser() { return getPropsUI().getLastRepositoryLogin(); } public void setCurrentRepository(RepositoryMeta repositoryMeta) { this.currentRepository = repositoryMeta; } public RepositoryMeta getCurrentRepository() { return this.currentRepository; } public RepositoryMeta getConnectedRepository() { return connectedRepository; } public void setConnectedRepository(RepositoryMeta connectedRepository) { this.connectedRepository = connectedRepository; } public RepositoryMeta getDefaultRepositoryMeta() { for (int i = 0; i < repositoriesMeta.nrRepositories(); i++) { RepositoryMeta repositoryMeta = repositoriesMeta.getRepository(i); if (repositoryMeta.isDefault()) { return repositoryMeta; } } return null; } public RepositoryMeta getRepositoryMetaByName(String name) { return repositoriesMeta.findRepository(name); } public boolean isConnected(String name) { if (spoonSupplier.get().rep != null) { return spoonSupplier.get().rep.getName().equals(name); } return false; } public boolean isConnected() { return spoonSupplier.get().rep != null; } public Repository getConnectedRepositoryInstance() { return spoonSupplier.get().rep; } public void save() { try { repositoriesMeta.writeData(); } catch (KettleException ke) { log.logError("Unable to write to repositories", ke); } } @SuppressWarnings("unchecked") private Repository wrapWithRepositoryTimeoutHandler(ReconnectableRepository repository) { List<Class<?>> repositoryIntrerfaces = ClassUtils.getAllInterfaces(repository.getClass()); Class<?>[] repositoryIntrerfacesArray = repositoryIntrerfaces .toArray(new Class<?>[repositoryIntrerfaces.size()]); return (Repository) Proxy.newProxyInstance(repository.getClass().getClassLoader(), repositoryIntrerfacesArray, new RepositorySessionTimeoutHandler(repository, this)); } public PropsUI getPropsUI() { return PropsUI.getInstance(); } public void addListener(RepositoryContollerListener listener) { listeners.add(listener); } public void fireListeners() { for (RepositoryContollerListener listener : listeners) { listener.update(); } } public interface RepositoryContollerListener { void update(); } public boolean isRelogin() { return relogin; } public void setRelogin(boolean relogin) { this.relogin = relogin; } public Map<String, Object> modelToMap(RepositoryModel model) { Map<String, Object> properties = new HashMap<>(); properties.put(DISPLAY_NAME, model.getDisplayName()); properties.put(DESCRIPTION, model.getDescription()); properties.put(IS_DEFAULT, model.getIsDefault()); properties.put(URL, model.getUrl()); properties.put(DATABASE_CONNECTION, model.getDatabaseConnection()); properties.put(SHOW_HIDDEN_FOLDERS, model.getShowHiddenFolders()); properties.put(LOCATION, model.getLocation()); properties.put(DO_NOT_MODIFY, model.getDoNotModify()); return properties; } }