/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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.jkiss.dbeaver.registry;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.connection.DBPClientHome;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPConnectionEventType;
import org.jkiss.dbeaver.model.data.DBDDataFormatterProfile;
import org.jkiss.dbeaver.model.data.DBDPreferences;
import org.jkiss.dbeaver.model.data.DBDValueHandler;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.exec.DBCTransactionManager;
import org.jkiss.dbeaver.model.impl.data.DefaultValueHandler;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.net.DBWNetworkHandler;
import org.jkiss.dbeaver.model.net.DBWTunnel;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.runtime.*;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.model.virtual.DBVModel;
import org.jkiss.dbeaver.registry.driver.DriverDescriptor;
import org.jkiss.dbeaver.registry.formatter.DataFormatterProfile;
import org.jkiss.dbeaver.runtime.TasksJob;
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
import org.jkiss.dbeaver.runtime.ui.DBUserInterface;
import org.jkiss.dbeaver.ui.actions.datasource.DataSourceHandler;
import org.jkiss.utils.CommonUtils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.util.*;
/**
* DataSourceDescriptor
*/
public class DataSourceDescriptor
implements
DBPDataSourceContainer,
DBPImageProvider,
IAdaptable,
DBPStatefulObject,
DBPRefreshableObject
{
private static final Log log = Log.getLog(DataSourceDescriptor.class);
@NotNull
private final DBPDataSourceRegistry registry;
@NotNull
private final DataSourceOrigin origin;
@NotNull
private DriverDescriptor driver;
@NotNull
private DBPConnectionConfiguration connectionInfo;
private DBPConnectionConfiguration tunnelConnectionInfo;
@NotNull
private String id;
private String name;
private String description;
private boolean savePassword;
private boolean showSystemObjects;
private boolean showUtilityObjects;
private boolean connectionReadOnly;
private final Map<String, FilterMapping> filterMap = new HashMap<>();
private DBDDataFormatterProfile formatterProfile;
@Nullable
private DBPClientHome clientHome;
@Nullable
private String lockPasswordHash;
@Nullable
private DataSourceFolder folder;
@NotNull
private DataSourcePreferenceStore preferenceStore;
@Nullable
private DBPDataSource dataSource;
private final List<DBPDataSourceUser> users = new ArrayList<>();
private volatile boolean connectFailed = false;
private volatile Date connectTime = null;
private volatile boolean disposed = false;
private volatile boolean connecting = false;
private boolean temporary;
private final List<DBRProcessDescriptor> childProcesses = new ArrayList<>();
private DBWTunnel tunnel;
@NotNull
private final DBVModel virtualModel;
public DataSourceDescriptor(
@NotNull DBPDataSourceRegistry registry,
@NotNull String id,
@NotNull DriverDescriptor driver,
@NotNull DBPConnectionConfiguration connectionInfo)
{
this(registry, ((DataSourceRegistry)registry).getDefaultOrigin(), id, driver, connectionInfo);
}
DataSourceDescriptor(
@NotNull DBPDataSourceRegistry registry,
@NotNull DataSourceOrigin origin,
@NotNull String id,
@NotNull DriverDescriptor driver,
@NotNull DBPConnectionConfiguration connectionInfo)
{
this.registry = registry;
this.origin = origin;
this.id = id;
this.driver = driver;
this.connectionInfo = connectionInfo;
this.preferenceStore = new DataSourcePreferenceStore(this);
this.virtualModel = new DBVModel(this);
}
// Copy constructor
public DataSourceDescriptor(@NotNull DataSourceDescriptor source)
{
this.registry = source.registry;
this.origin = source.origin;
this.id = source.id;
this.name = source.name;
this.description = source.description;
this.savePassword = source.savePassword;
this.showSystemObjects = source.showSystemObjects;
this.showUtilityObjects = source.showUtilityObjects;
this.connectionReadOnly = source.connectionReadOnly;
this.driver = source.driver;
this.connectionInfo = source.connectionInfo;
this.formatterProfile = source.formatterProfile;
this.clientHome = source.clientHome;
this.connectionInfo = new DBPConnectionConfiguration(source.connectionInfo);
for (Map.Entry<String, FilterMapping> fe : source.filterMap.entrySet()) {
this.filterMap.put(fe.getKey(), new FilterMapping(fe.getValue()));
}
this.lockPasswordHash = source.lockPasswordHash;
this.folder = source.folder;
this.preferenceStore = new DataSourcePreferenceStore(this);
this.virtualModel = new DBVModel(this, source.virtualModel);
}
public boolean isDisposed()
{
return disposed;
}
public void dispose()
{
if (disposed) {
log.warn("Dispose of already disposed data source");
return;
}
synchronized (users) {
users.clear();
}
disposed = true;
}
@NotNull
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@NotNull
@Override
public DriverDescriptor getDriver()
{
return driver;
}
@NotNull
@Override
public DBPPlatform getPlatform() {
return registry.getPlatform();
}
public void setDriver(@NotNull DriverDescriptor driver)
{
this.driver = driver;
}
@NotNull
@Override
public DBPConnectionConfiguration getConnectionConfiguration()
{
return connectionInfo;
}
public void setConnectionInfo(@NotNull DBPConnectionConfiguration connectionInfo)
{
this.connectionInfo = connectionInfo;
}
@NotNull
@Override
public DBPConnectionConfiguration getActualConnectionConfiguration()
{
return tunnelConnectionInfo != null ? tunnelConnectionInfo : connectionInfo;
}
@NotNull
@Override
@Property(viewable = true, order = 1)
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Nullable
@Override
@Property(viewable = true, order = 2)
public String getDescription()
{
return description;
}
public boolean isSavePassword()
{
return savePassword;
}
public void setSavePassword(boolean savePassword)
{
this.savePassword = savePassword;
}
@Override
public boolean isShowSystemObjects()
{
return showSystemObjects;
}
public void setShowSystemObjects(boolean showSystemObjects)
{
this.showSystemObjects = showSystemObjects;
}
@Override
public boolean isShowUtilityObjects() {
return showUtilityObjects;
}
public void setShowUtilityObjects(boolean showUtilityObjects) {
this.showUtilityObjects = showUtilityObjects;
}
@Override
public boolean isConnectionReadOnly()
{
return connectionReadOnly;
}
public void setConnectionReadOnly(boolean connectionReadOnly)
{
this.connectionReadOnly = connectionReadOnly;
}
@Override
public boolean isDefaultAutoCommit()
{
if (connectionInfo.getBootstrap().getDefaultAutoCommit() != null) {
return connectionInfo.getBootstrap().getDefaultAutoCommit();
} else {
return getConnectionConfiguration().getConnectionType().isAutocommit();
}
}
@Override
public void setDefaultAutoCommit(final boolean autoCommit, DBCExecutionContext updateContext, boolean updateConnection, final Runnable onFinish) throws DBException {
if (updateContext != null) {
final DBCTransactionManager txnManager = DBUtils.getTransactionManager(updateContext);
if (updateConnection && txnManager != null) {
TasksJob.runTask("Set auto-commit mode", new DBRRunnableWithProgress() {
@Override
public void run(DBRProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
try {
// Change auto-commit mode
txnManager.setAutoCommit(monitor, autoCommit);
} catch (DBCException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
if (onFinish != null) {
onFinish.run();
}
}
}
});
}
}
// Save in preferences
if (autoCommit == getConnectionConfiguration().getConnectionType().isAutocommit()) {
connectionInfo.getBootstrap().setDefaultAutoCommit(null);
} else {
connectionInfo.getBootstrap().setDefaultAutoCommit(autoCommit);
}
}
@Nullable
@Override
public DBPTransactionIsolation getActiveTransactionsIsolation()
{
if (dataSource != null) {
DBCTransactionManager txnManager = DBUtils.getTransactionManager(dataSource.getDefaultContext(false));
if (txnManager != null) {
try {
return txnManager.getTransactionIsolation();
} catch (DBCException e) {
log.debug("Can't determine isolation level", e);
return null;
}
}
}
return null;
}
@Override
public Integer getDefaultTransactionsIsolation() {
return connectionInfo.getBootstrap().getDefaultTransactionIsolation();
}
@Override
public void setDefaultTransactionsIsolation(@Nullable final DBPTransactionIsolation isolationLevel) throws DBException {
if (isolationLevel == null) {
connectionInfo.getBootstrap().setDefaultTransactionIsolation(null);
} else {
connectionInfo.getBootstrap().setDefaultTransactionIsolation(isolationLevel.getCode());
if (dataSource != null) {
TasksJob.runTask("Set transactions isolation level", new DBRRunnableWithProgress() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
DBCTransactionManager txnManager = DBUtils.getTransactionManager(dataSource.getDefaultContext(false));
if (txnManager != null) {
try {
if (!txnManager.getTransactionIsolation().equals(isolationLevel)) {
txnManager.setTransactionIsolation(monitor, isolationLevel);
}
} catch (DBCException e) {
throw new InvocationTargetException(e);
}
}
}
});
}
}
}
public void setDefaultActiveObject(String defaultActiveObject) {
connectionInfo.getBootstrap().setDefaultObjectName(defaultActiveObject);
}
public Collection<FilterMapping> getObjectFilters()
{
return filterMap.values();
}
@Nullable
@Override
public DBSObjectFilter getObjectFilter(Class<?> type, @Nullable DBSObject parentObject, boolean firstMatch)
{
FilterMapping filterMapping = getFilterMapping(type, parentObject, firstMatch);
if (filterMapping != null) {
return filterMapping.getFilter(parentObject, firstMatch);
}
return null;
}
@Nullable
private FilterMapping getFilterMapping(Class<?> type, @Nullable DBSObject parentObject, boolean firstMatch)
{
if (filterMap.isEmpty()) {
return null;
}
// Test all super classes
for (Class<?> testType = type; testType != null; testType = testType.getSuperclass()) {
FilterMapping filterMapping = filterMap.get(testType.getName());
DBSObjectFilter filter;
if (filterMapping == null) {
// Try to find using interfaces and superclasses
for (Class<?> it : testType.getInterfaces()) {
filterMapping = filterMap.get(it.getName());
if (filterMapping != null) {
filter = filterMapping.getFilter(parentObject, firstMatch);
if (filter != null && (firstMatch || filter.isEnabled())) return filterMapping;
}
}
}
if (filterMapping != null) {
filter = filterMapping.getFilter(parentObject, firstMatch);
if (filter != null && (firstMatch || !filter.isNotApplicable())) {
return filterMapping;
}
}
}
return null;
}
@Override
public void setObjectFilter(Class<?> type, DBSObject parentObject, DBSObjectFilter filter)
{
FilterMapping filterMapping = getFilterMapping(type, parentObject, true);
if (filterMapping != null) {
// Update filter
if (parentObject == null) {
filterMapping.defaultFilter = filter;
} else {
filterMapping.customFilters.put(DBUtils.getObjectUniqueName(parentObject), filter);
}
}
updateObjectFilter(type.getName(), parentObject == null ? null : DBUtils.getObjectUniqueName(parentObject), filter);
}
void clearFilters() {
filterMap.clear();
}
void updateObjectFilter(String typeName, @Nullable String objectID, DBSObjectFilter filter)
{
FilterMapping filterMapping = filterMap.get(typeName);
if (filterMapping == null) {
filterMapping = new FilterMapping(typeName);
filterMap.put(typeName, filterMapping);
}
if (objectID == null) {
filterMapping.defaultFilter = filter;
} else {
filterMapping.customFilters.put(objectID, filter);
}
}
@Override
@NotNull
public DBVModel getVirtualModel()
{
return virtualModel;
}
@Override
public DBPClientHome getClientHome()
{
if (clientHome == null && !CommonUtils.isEmpty(connectionInfo.getClientHomeId())) {
this.clientHome = driver.getClientHome(connectionInfo.getClientHomeId());
}
return clientHome;
}
@Override
public DBWNetworkHandler[] getActiveNetworkHandlers() {
if (tunnel == null) {
return new DBWNetworkHandler[0];
}
return new DBWNetworkHandler[] { tunnel };
}
@NotNull
DataSourceOrigin getOrigin() {
return origin;
}
@Override
public boolean isProvided() {
return !origin.isDefault();
}
@Override
public boolean isTemporary() {
return temporary;
}
public void setTemporary(boolean temporary) {
this.temporary = temporary;
}
@Override
public DBSObject getParentObject()
{
return null;
}
@Override
public DBSObject refreshObject(@NotNull DBRProgressMonitor monitor)
throws DBException
{
if (dataSource instanceof DBPRefreshableObject) {
dataSource = (DBPDataSource) ((DBPRefreshableObject) dataSource).refreshObject(monitor);
} else {
this.reconnect(monitor, false);
}
getRegistry().notifyDataSourceListeners(new DBPEvent(
DBPEvent.Action.OBJECT_UPDATE,
DataSourceDescriptor.this));
return this;
}
public void setDescription(@Nullable String description)
{
this.description = description;
}
public Date getConnectTime() {
return connectTime;
}
public boolean isLocked() {
return !CommonUtils.isEmpty(lockPasswordHash);
}
@Nullable
public String getLockPasswordHash() {
return lockPasswordHash;
}
void setLockPasswordHash(@Nullable String lockPasswordHash) {
this.lockPasswordHash = lockPasswordHash;
}
@Nullable
@Override
public DBPDataSource getDataSource()
{
return dataSource;
}
@Nullable
@Override
public DataSourceFolder getFolder() {
return folder;
}
@Override
public void setFolder(@Nullable DBPDataSourceFolder folder) {
this.folder = (DataSourceFolder) folder;
}
@Override
public boolean isPersisted()
{
return true;
}
@NotNull
@Override
public DBPDataSourceRegistry getRegistry()
{
return registry;
}
@Override
public void persistConfiguration()
{
registry.flushConfig();
}
@Override
public boolean isConnected()
{
return dataSource != null;
}
@Override
public void initConnection(DBRProgressMonitor monitor, DBRProgressListener onFinish) {
DataSourceHandler.connectToDataSource(monitor, this, onFinish);
}
public boolean connect(DBRProgressMonitor monitor, boolean initialize, boolean reflect)
throws DBException
{
if (connecting) {
log.debug("Can't connect - connect/disconnect is in progress");
return false;
}
if (this.isConnected()) {
log.debug("Can't connect - already connected");
return false;
}
log.debug("Connect with '" + getName() + "' (" + getId() + ")");
//final String oldName = getConnectionConfiguration().getUserName();
//final String oldPassword = getConnectionConfiguration().getUserPassword();
if (!isSavePassword()) {
// Ask for password
if (!DataSourceHandler.askForPassword(this, null, false)) {
DataSourceHandler.updateDataSourceObject(this);
return false;
}
}
processEvents(monitor, DBPConnectionEventType.BEFORE_CONNECT);
connecting = true;
tunnelConnectionInfo = null;
try {
// Handle tunnel
// Open tunnel and replace connection info with new one
this.tunnel = null;
DBWHandlerConfiguration tunnelConfiguration = null;
for (DBWHandlerConfiguration handler : connectionInfo.getDeclaredHandlers()) {
if (handler.isEnabled() && handler.getType() == DBWHandlerType.TUNNEL) {
tunnelConfiguration = handler;
break;
}
}
monitor.beginTask("Connect to " + getName(), tunnelConfiguration != null ? 3 : 2);
if (tunnelConfiguration != null) {
monitor.subTask("Initialize tunnel");
tunnel = tunnelConfiguration.createHandler(DBWTunnel.class);
try {
if (!tunnelConfiguration.isSavePassword()) {
DBWTunnel.AuthCredentials rc = tunnel.getRequiredCredentials(tunnelConfiguration);
if (!DataSourceHandler.askForPassword(this, tunnelConfiguration, rc == DBWTunnel.AuthCredentials.PASSWORD)) {
DataSourceHandler.updateDataSourceObject(this);
tunnel = null;
return false;
}
}
/*
for (DBWHandlerConfiguration handler : getConnectionConfiguration().getDeclaredHandlers()) {
if (handler.isEnabled() && handler.isSecured() && !handler.isSavePassword()) {
if (!DataSourceHandler.askForPassword(this, handler)) {
DataSourceHandler.updateDataSourceObject(this);
return false;
}
}
}
*/
tunnelConnectionInfo = tunnel.initializeTunnel(monitor, registry.getPlatform(), tunnelConfiguration, connectionInfo);
} catch (Exception e) {
throw new DBCException("Can't initialize tunnel", e);
}
monitor.worked(1);
}
monitor.subTask("Connect to data source");
dataSource = getDriver().getDataSourceProvider().openDataSource(monitor, this);
monitor.worked(1);
if (initialize) {
monitor.subTask("Initialize data source");
try {
dataSource.initialize(monitor);
} catch (Throwable e) {
log.error("Error initializing datasource", e);
}
// Change connection properties
initConnectionState(monitor);
}
connectFailed = false;
connectTime = new Date();
processEvents(monitor, DBPConnectionEventType.AFTER_CONNECT);
if (reflect) {
getRegistry().notifyDataSourceListeners(new DBPEvent(
DBPEvent.Action.OBJECT_UPDATE,
DataSourceDescriptor.this,
true));
}
try {
log.debug("Connected (" + getId() + ", " + getPropertyDriver() + ")");
} catch (Throwable e) {
log.debug("Connected (" + getId() + ", driver unknown)");
}
return true;
} catch (Exception e) {
log.debug("Connection failed (" + getId() + ")");
if (tunnel != null) {
try {
tunnel.closeTunnel(monitor);
} catch (IOException e1) {
log.error("Error closing tunnel", e);
} finally {
tunnel = null;
tunnelConnectionInfo = null;
}
}
// Failed
connectFailed = true;
//if (reflect) {
getRegistry().notifyDataSourceListeners(new DBPEvent(
DBPEvent.Action.OBJECT_UPDATE,
DataSourceDescriptor.this,
false));
//}
if (e instanceof DBException) {
throw (DBException)e;
} else {
throw new DBException("Internal error connecting to " + getName(), e);
}
} finally {
monitor.done();
connecting = false;
}
}
private void initConnectionState(DBRProgressMonitor monitor) throws DBException {
if (dataSource == null) {
return;
}
// Set active object
if (dataSource instanceof DBSObjectSelector && dataSource instanceof DBSObjectContainer) {
String activeObject = getConnectionConfiguration().getBootstrap().getDefaultObjectName();
if (!CommonUtils.isEmptyTrimmed(activeObject)) {
DBSObject child = ((DBSObjectContainer) dataSource).getChild(monitor, activeObject);
if (child != null) {
try {
((DBSObjectSelector) dataSource).setDefaultObject(monitor, child);
} catch (DBException e) {
log.warn("Can't select active object", e);
}
} else {
log.debug("Object '" + activeObject + "' not found");
}
}
}
}
private void processEvents(DBRProgressMonitor monitor, DBPConnectionEventType eventType)
{
DBPConnectionConfiguration info = getActualConnectionConfiguration();
DBRShellCommand command = info.getEvent(eventType);
if (command != null && command.isEnabled()) {
Map<String, Object> variables = new HashMap<>();
for (Map.Entry<String, String> entry : info.getProperties().entrySet()) {
variables.put(CommonUtils.toString(entry.getKey()), entry.getValue());
}
variables.put(RegistryConstants.VARIABLE_HOST, info.getHostName());
variables.put(RegistryConstants.VARIABLE_PORT, info.getHostPort());
variables.put(RegistryConstants.VARIABLE_SERVER, info.getServerName());
variables.put(RegistryConstants.VARIABLE_DATABASE, info.getDatabaseName());
variables.put(RegistryConstants.VARIABLE_USER, info.getUserName());
variables.put(RegistryConstants.VARIABLE_PASSWORD, info.getUserPassword());
variables.put(RegistryConstants.VARIABLE_URL, info.getUrl());
final DBRProcessDescriptor processDescriptor = new DBRProcessDescriptor(command, variables);
monitor.subTask("Execute process " + processDescriptor.getName());
DBUserInterface.getInstance().executeProcess(processDescriptor);
if (command.isWaitProcessFinish()) {
if (command.getWaitProcessTimeoutMs() >= 0) {
processDescriptor.waitFor(command.getWaitProcessTimeoutMs());
} else {
processDescriptor.waitFor();
}
}
addChildProcess(processDescriptor);
}
}
@Override
public boolean disconnect(final DBRProgressMonitor monitor)
throws DBException
{
return disconnect(monitor, true);
}
public boolean disconnect(final DBRProgressMonitor monitor, boolean reflect)
throws DBException
{
if (dataSource == null) {
log.error("Datasource is not connected");
return true;
}
if (connecting) {
log.error("Connect/disconnect is in progress");
return false;
}
connecting = true;
try {
releaseDataSourceUsers(monitor);
monitor.beginTask("Disconnect from '" + getName() + "'", 5 + dataSource.getAllContexts().length);
processEvents(monitor, DBPConnectionEventType.BEFORE_DISCONNECT);
monitor.worked(1);
// Close datasource
monitor.subTask("Close connection");
if (dataSource != null) {
dataSource.shutdown(monitor);
}
monitor.worked(1);
// Close tunnel
if (tunnel != null) {
monitor.subTask("Close tunnel");
try {
tunnel.closeTunnel(monitor);
} catch (Throwable e) {
log.error("Error closing tunnel", e);
}
}
monitor.worked(1);
processEvents(monitor, DBPConnectionEventType.AFTER_DISCONNECT);
monitor.worked(1);
monitor.done();
// Terminate child processes
synchronized (childProcesses) {
for (Iterator<DBRProcessDescriptor> iter = childProcesses.iterator(); iter.hasNext(); ) {
DBRProcessDescriptor process = iter.next();
if (process.isRunning() && process.getCommand().isTerminateAtDisconnect()) {
process.terminate();
}
iter.remove();
}
}
dataSource = null;
connectTime = null;
if (reflect) {
// Reflect UI
getRegistry().notifyDataSourceListeners(new DBPEvent(
DBPEvent.Action.OBJECT_UPDATE,
this,
false));
}
return true;
} finally {
connecting = false;
log.debug("Disconnected (" + getId() + ")");
}
}
private void releaseDataSourceUsers(DBRProgressMonitor monitor) {
List<DBPDataSourceUser> usersStamp;
synchronized (users) {
usersStamp = new ArrayList<>(users);
}
int jobCount = 0;
// Save all unsaved data
for (DBPDataSourceUser user : usersStamp) {
if (user instanceof Job) {
jobCount++;
}
if (user instanceof DBPDataSourceHandler) {
((DBPDataSourceHandler) user).beforeDisconnect();
}
}
if (jobCount > 0) {
monitor.beginTask("Waiting for all active tasks to finish", jobCount);
// Stop all jobs
for (DBPDataSourceUser user : usersStamp) {
if (user instanceof Job) {
Job job = (Job) user;
monitor.subTask("Stop '" + job.getName() + "'");
if (job.getState() == Job.RUNNING) {
job.cancel();
try {
// Wait for 3 seconds
for (int i = 0; i < 30; i++) {
Thread.sleep(100);
if (job.getState() != Job.RUNNING) {
break;
}
}
} catch (InterruptedException e) {
// its ok, do nothing
}
}
monitor.worked(1);
}
}
monitor.done();
}
}
@Override
public boolean reconnect(final DBRProgressMonitor monitor)
throws DBException
{
return reconnect(monitor, true);
}
public boolean reconnect(final DBRProgressMonitor monitor, boolean reflect)
throws DBException
{
if (connecting) {
log.debug("Can't reconnect - connect/disconnect is in progress");
return false;
}
if (isConnected()) {
if (!disconnect(monitor, reflect)) {
return false;
}
}
return connect(monitor, true, reflect);
}
@Override
public Collection<DBPDataSourceUser> getUsers()
{
synchronized (users) {
return new ArrayList<>(users);
}
}
@Override
public void acquire(DBPDataSourceUser user)
{
synchronized (users) {
if (users.contains(user)) {
log.warn("Datasource user '" + user + "' already registered in datasource '" + getName() + "'");
} else {
users.add(user);
}
}
}
@Override
public void release(DBPDataSourceUser user)
{
synchronized (users) {
if (!users.remove(user)) {
if (!isDisposed()) {
log.warn("Datasource user '" + user + "' is not registered in datasource '" + getName() + "'");
}
}
}
}
@Override
public void fireEvent(DBPEvent event) {
registry.notifyDataSourceListeners(event);
}
@Override
public DBDDataFormatterProfile getDataFormatterProfile()
{
if (this.formatterProfile == null) {
this.formatterProfile = new DataFormatterProfile(getId(), preferenceStore);
}
return this.formatterProfile;
}
@Override
public void setDataFormatterProfile(DBDDataFormatterProfile formatterProfile)
{
this.formatterProfile = formatterProfile;
}
@NotNull
@Override
public DBDValueHandler getDefaultValueHandler()
{
if (dataSource instanceof DBDPreferences) {
return ((DBDPreferences) dataSource).getDefaultValueHandler();
}
return DefaultValueHandler.INSTANCE;
}
@NotNull
@Override
public DataSourcePreferenceStore getPreferenceStore()
{
return preferenceStore;
}
public void resetPassword()
{
connectionInfo.setUserPassword(null);
}
@Nullable
@Override
public <T> T getAdapter(Class<T> adapter)
{
if (DBPDataSourceContainer.class.isAssignableFrom(adapter)) {
return adapter.cast(this);
} else if (adapter == DBPPropertySource.class) {
PropertyCollector coll = new PropertyCollector(this, true);
coll.collectProperties();
if (dataSource != null) {
int conIndex = 0;
for (DBCExecutionContext context : dataSource.getAllContexts()) {
conIndex++;
coll.addProperty("Connections", conIndex, String.valueOf(conIndex), new ContextInfo(context));
}
}
return adapter.cast(coll);
}
return null;
}
@Override
@NotNull
public DBPImage getObjectImage()
{
return driver.getPlainIcon();
}
@NotNull
@Override
public DBSObjectState getObjectState()
{
if (isConnected()) {
return DBSObjectState.ACTIVE;
} else if (connectFailed) {
return DBSObjectState.INVALID;
} else {
return DBSObjectState.NORMAL;
}
}
@Override
public void refreshObjectState(@NotNull DBRProgressMonitor monitor)
{
// just do nothing
}
public static String generateNewId(DriverDescriptor driver)
{
long rnd = new Random().nextLong();
if (rnd < 0) rnd = -rnd;
return driver.getId() + "-" + Long.toHexString(System.currentTimeMillis()) + "-" + Long.toHexString(rnd);
}
@Property(viewable = true, order = 20, category = "Driver")
public String getPropertyDriverType()
{
return driver.getName();
}
@Property(order = 3, category = "Server")
public String getPropertyAddress()
{
StringBuilder addr = new StringBuilder();
if (!CommonUtils.isEmpty(connectionInfo.getHostName())) {
addr.append(connectionInfo.getHostName());
}
if (!CommonUtils.isEmpty(connectionInfo.getHostPort())) {
addr.append(':').append(connectionInfo.getHostPort());
}
return addr.toString();
}
@Property(order = 4, category = "Server")
public String getPropertyDatabase()
{
return connectionInfo.getDatabaseName();
}
@Property(order = 5, category = "Server")
public String getPropertyURL()
{
return connectionInfo.getUrl();
}
@Nullable
@Property(order = 6, category = "Server")
public String getPropertyServerName()
{
if (dataSource != null) {
String serverName = dataSource.getInfo().getDatabaseProductName();
String serverVersion = dataSource.getInfo().getDatabaseProductVersion();
if (serverName != null) {
return serverName + (serverVersion == null ? "" : " [" + serverVersion + "]");
}
}
return null;
}
@Nullable
@Property(order = 21, category = "Driver")
public String getPropertyDriver()
{
if (dataSource != null) {
String driverName = dataSource.getInfo().getDriverName();
String driverVersion = dataSource.getInfo().getDriverVersion();
if (driverName != null) {
return driverName + (driverVersion == null ? "" : " [" + driverVersion + "]");
}
}
return null;
}
@Nullable
@Property(order = 8)
public String getPropertyConnectTime()
{
if (connectTime != null) {
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(connectTime);
}
return null;
}
@Property(order = 9)
public String getPropertyConnectType()
{
return connectionInfo.getConnectionType().getName();
}
public void addChildProcess(DBRProcessDescriptor process)
{
synchronized (childProcesses) {
childProcesses.add(process);
}
}
public void copyFrom(DataSourceDescriptor descriptor) {
filterMap.clear();
for (FilterMapping mapping : descriptor.getObjectFilters()) {
filterMap.put(mapping.typeName, new FilterMapping(mapping));
}
virtualModel.copyFrom(descriptor.getVirtualModel());
setDescription(descriptor.getDescription());
setSavePassword(descriptor.isSavePassword());
setShowSystemObjects(descriptor.isShowSystemObjects());
setShowUtilityObjects(descriptor.isShowUtilityObjects());
setConnectionReadOnly(descriptor.isConnectionReadOnly());
}
@Override
@NotNull
public ISecurePreferences getSecurePreferences() {
return registry.getSecurePreferences().node(id);
}
@Override
public String toString() {
return name + " [" + driver + "]";
}
public boolean equalSettings(Object obj) {
if (!(obj instanceof DataSourceDescriptor)) {
return false;
}
DataSourceDescriptor source = (DataSourceDescriptor) obj;
return
CommonUtils.equalObjects(this.name, source.name) &&
CommonUtils.equalObjects(this.description, source.description) &&
CommonUtils.equalObjects(this.savePassword, source.savePassword) &&
CommonUtils.equalObjects(this.showSystemObjects, source.showSystemObjects) &&
CommonUtils.equalObjects(this.showUtilityObjects, source.showUtilityObjects) &&
CommonUtils.equalObjects(this.connectionReadOnly, source.connectionReadOnly) &&
CommonUtils.equalObjects(this.driver, source.driver) &&
CommonUtils.equalObjects(this.connectionInfo, source.connectionInfo) &&
CommonUtils.equalObjects(this.filterMap, source.filterMap) &&
CommonUtils.equalObjects(this.formatterProfile, source.formatterProfile) &&
CommonUtils.equalObjects(this.clientHome, source.clientHome) &&
CommonUtils.equalObjects(this.lockPasswordHash, source.lockPasswordHash) &&
CommonUtils.equalObjects(this.folder, source.folder);
}
public static class ContextInfo implements DBPObject {
private final DBCExecutionContext context;
public ContextInfo(DBCExecutionContext context) {
this.context = context;
}
@Property(viewable = true, order = 1)
public String getName() {
return context.getContextName();
}
@Override
public String toString() {
return getName();
}
}
}