/*
* 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.ui.controls.txn;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IWorkbenchPart;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.qm.QMTransactionState;
import org.jkiss.dbeaver.model.qm.QMUtils;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceRegistry;
import org.jkiss.dbeaver.ui.DBeaverIcons;
import org.jkiss.dbeaver.ui.UIIcon;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.actions.datasource.DataSourceCommitHandler;
import org.jkiss.dbeaver.ui.actions.datasource.DataSourceRollbackHandler;
import org.jkiss.utils.ArrayUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class PendingTransactionsDialog extends TransactionInfoDialog {
private static final String DIALOG_ID = "DBeaver.PendingTransactionsDialog";//$NON-NLS-1$
private Tree contextTree;
private DBCExecutionContext selectedContext;
private Button commitButton;
private Button rollbackButton;
public PendingTransactionsDialog(Shell parentShell, IWorkbenchPart activePart) {
super(parentShell, activePart);
}
@Override
protected boolean isResizable() {
return true;
}
@Override
protected DBCExecutionContext getCurrentContext() {
return selectedContext;
}
protected IDialogSettings getDialogBoundsSettings()
{
return UIUtils.getDialogSettings(DIALOG_ID);
}
@Override
protected Control createDialogArea(Composite parent)
{
getShell().setText("Pending transactions");
Composite composite = (Composite) super.createDialogArea(parent);
contextTree = new Tree(composite, SWT.FULL_SELECTION | SWT.BORDER);
contextTree.setHeaderVisible(true);
contextTree.setLinesVisible(true);
TreeColumn colName = new TreeColumn(contextTree, SWT.NONE);
colName.setText("Connection");
TreeColumn colTxn = new TreeColumn(contextTree, SWT.RIGHT);
colTxn.setText("Transaction");
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = contextTree.getHeaderHeight() + contextTree.getItemHeight() * 5;
contextTree.setLayoutData(gd);
contextTree.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (e.item != null && e.item.getData() instanceof DBCExecutionContext) {
selectedContext = (DBCExecutionContext) e.item.getData();
} else {
selectedContext = null;
}
boolean hasTransaction = selectedContext != null && QMUtils.isTransactionActive(selectedContext);
commitButton.setEnabled(hasTransaction);
rollbackButton.setEnabled(hasTransaction);
logViewer.setFilter(createContextFilter(selectedContext));
logViewer.refresh();
}
});
{
Composite controlPanel = UIUtils.createPlaceholder(composite, 3, 5);
controlPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Button showAllCheck = UIUtils.createCheckbox(controlPanel, "Show all connections", "Show all datasource connections. Otherwise shows only transactional connections.", false, 1);
showAllCheck.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
loadContexts(showAllCheck.getSelection());
}
});
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.grabExcessHorizontalSpace = true;
showAllCheck.setLayoutData(gd);
commitButton = UIUtils.createPushButton(controlPanel, "Commit", DBeaverIcons.getImage(UIIcon.TXN_COMMIT));
commitButton.setEnabled(false);
commitButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
endTransaction(true);
}
});
rollbackButton = UIUtils.createPushButton(controlPanel, "Rollback", DBeaverIcons.getImage(UIIcon.TXN_ROLLBACK));
rollbackButton.setEnabled(false);
rollbackButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
endTransaction(false);
}
});
}
super.createTransactionLogPanel(composite);
loadContexts(false);
return parent;
}
private void endTransaction(boolean commit) {
if (selectedContext == null) {
return;
}
if (commit) {
DataSourceCommitHandler.execute(selectedContext);
} else {
DataSourceRollbackHandler.execute(selectedContext);
}
commitButton.setEnabled(false);
rollbackButton.setEnabled(false);
}
private void loadContexts(boolean showAllContexts) {
contextTree.removeAll();
// Load all open context
for (DataSourceDescriptor dataSource : DataSourceRegistry.getAllDataSources()) {
if (!dataSource.isConnected() || dataSource.getDataSource() == null) {
continue;
}
DBCExecutionContext[] allContexts = dataSource.getDataSource().getAllContexts();
if (ArrayUtils.isEmpty(allContexts)) {
continue;
}
List<DBCExecutionContext> txnContexts = new ArrayList<>();
for (DBCExecutionContext context : allContexts) {
if (showAllContexts || QMUtils.isTransactionActive(context)) {
txnContexts.add(context);
}
}
if (txnContexts.isEmpty()) {
continue;
}
TreeItem dsItem = new TreeItem(contextTree, SWT.NONE);
dsItem.setText(dataSource.getName());
dsItem.setImage(DBeaverIcons.getImage(dataSource.getObjectImage()));
dsItem.setData(dataSource);
for (DBCExecutionContext context : txnContexts) {
QMTransactionState txnState = QMUtils.getTransactionState(context);
TreeItem contextItem = new TreeItem(dsItem, SWT.NONE);
contextItem.setText(0, context.getContextName());
String stateString = String.valueOf(txnState.getUpdateCount()) + "/" + String.valueOf(txnState.getExecuteCount());
contextItem.setText(1, stateString);
contextItem.setData(context);
}
dsItem.setExpanded(true);
}
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
UIUtils.packColumns(contextTree);
}
});
}
public static void showDialog(Shell shell) {
IWorkbenchPart activePart = DBeaverUI.getActiveWorkbenchWindow().getActivePage().getActivePart();
if (activePart == null) {
UIUtils.showErrorDialog(
shell,
"No active part",
"No active part.");
} else {
final PendingTransactionsDialog dialog = new PendingTransactionsDialog(shell, activePart);
dialog.open();
}
}
}