package rocks.inspectit.ui.rcp.view.impl;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.ISources;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import rocks.inspectit.shared.all.cmr.model.PlatformIdent;
import rocks.inspectit.shared.all.exception.BusinessException;
import rocks.inspectit.shared.all.serializer.SerializationException;
import rocks.inspectit.shared.all.util.ObjectUtils;
import rocks.inspectit.shared.cs.storage.IStorageData;
import rocks.inspectit.shared.cs.storage.LocalStorageData;
import rocks.inspectit.shared.cs.storage.StorageData;
import rocks.inspectit.shared.cs.storage.StorageData.StorageState;
import rocks.inspectit.shared.cs.storage.label.AbstractStorageLabel;
import rocks.inspectit.shared.cs.storage.label.type.AbstractStorageLabelType;
import rocks.inspectit.ui.rcp.InspectIT;
import rocks.inspectit.ui.rcp.InspectITImages;
import rocks.inspectit.ui.rcp.action.MenuAction;
import rocks.inspectit.ui.rcp.filter.FilterComposite;
import rocks.inspectit.ui.rcp.form.StorageDataPropertyForm;
import rocks.inspectit.ui.rcp.formatter.ImageFormatter;
import rocks.inspectit.ui.rcp.formatter.TextFormatter;
import rocks.inspectit.ui.rcp.handlers.CloseAndShowStorageHandler;
import rocks.inspectit.ui.rcp.handlers.ShowRepositoryHandler;
import rocks.inspectit.ui.rcp.model.Component;
import rocks.inspectit.ui.rcp.model.GroupedLabelsComposite;
import rocks.inspectit.ui.rcp.model.storage.LocalStorageLeaf;
import rocks.inspectit.ui.rcp.model.storage.LocalStorageTreeModelManager;
import rocks.inspectit.ui.rcp.model.storage.StorageLeaf;
import rocks.inspectit.ui.rcp.model.storage.StorageTreeModelManager;
import rocks.inspectit.ui.rcp.provider.ILocalStorageDataProvider;
import rocks.inspectit.ui.rcp.provider.IStorageDataProvider;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryChangeListener;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition.OnlineStatus;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryManager;
import rocks.inspectit.ui.rcp.repository.RepositoryDefinition;
import rocks.inspectit.ui.rcp.repository.StorageRepositoryDefinition;
import rocks.inspectit.ui.rcp.storage.InspectITStorageManager;
import rocks.inspectit.ui.rcp.storage.listener.StorageChangeListener;
import rocks.inspectit.ui.rcp.util.SafeExecutor;
import rocks.inspectit.ui.rcp.view.IRefreshableView;
import rocks.inspectit.ui.rcp.view.tree.StorageManagerTreeContentProvider;
import rocks.inspectit.ui.rcp.view.tree.StorageManagerTreeLabelProvider;
/**
*
* @author Ivan Senic
*
*/
public class StorageManagerView extends ViewPart implements CmrRepositoryChangeListener, StorageChangeListener, IRefreshableView { // NOPMD
/**
* View id.
*/
public static final String VIEW_ID = "rocks.inspectit.ui.rcp.view.storageManager";
/**
* Menu id.
*/
public static final String MENU_ID = "rocks.inspectit.ui.rcp.view.storageManager.storageTree";
/**
* {@link CmrRepositoryManager}.
*/
private final CmrRepositoryManager cmrRepositoryManager;
/**
* {@link InspectITStorageManager}.
*/
private final InspectITStorageManager storageManager;
/**
* Map of storages and their repositories.
*/
private final Map<StorageData, CmrRepositoryDefinition> storageRepositoryMap = new ConcurrentHashMap<>();
/**
* Cashed statuses of CMR repository definitions.
*/
private final ConcurrentHashMap<CmrRepositoryDefinition, OnlineStatus> cachedOnlineStatus = new ConcurrentHashMap<>();
/**
* Set of downloaded storages.
*/
private final Set<LocalStorageData> downloadedStorages = Collections.newSetFromMap(new ConcurrentHashMap<LocalStorageData, Boolean>());
/**
* Toolkit for decorations.
*/
private FormToolkit toolkit;
/**
* Main form.
*/
private Form mainForm;
/**
* Tree Viewer.
*/
private TreeViewer treeViewer;
/**
* Filter for the tree.
*/
private final TreeFilter treeFilter = new TreeFilter();
/**
* Composite for message displaying.
*/
private Composite cmrMessageComposite;
/**
* Label type that storages are ordered by.
*/
private AbstractStorageLabelType<?> orderingLabelType = null;
/**
* Menu manager for filter repositories actions. Needed because it must be updated when the
* storages are added/removed.
*/
private MenuManager filterByRepositoryMenu;
/**
* Menu manager for grouping storage by label. Needed because it must be updated when the
* storages are added/removed.
*/
private MenuManager groupByLabelMenu;
/**
* Menu manager for filtering the storages based on the state.
*/
private MenuManager filterByStateMenu;
/**
* Storage property form.
*/
private StorageDataPropertyForm storagePropertyForm;
/**
* Last selected leaf.
*/
private StorageLeaf lastSelectedLeaf = null;
/**
* Last selected local storage leaf.
*/
private LocalStorageLeaf lastSelectedLocalStorageLeaf = null;
/**
* Boolean for layout of view.
*/
private boolean verticaLayout = true;
/**
* Views main composite.
*/
private SashForm mainComposite;
/**
* Upper composite where filter box and storage tree is located.
*/
private Composite upperComposite;
/**
* Filter storages composite that will be displayed at top of view.
*/
private FilterStorageComposite filterStorageComposite;
/**
* Selection button for showing the remove storages.
*/
private Button remoteStorageSelection;
/**
* Selection button for showing the local storages.
*/
private Button localStorageSelection;
/**
* Default constructor.
*/
public StorageManagerView() {
cmrRepositoryManager = InspectIT.getDefault().getCmrRepositoryManager();
cmrRepositoryManager.addCmrRepositoryChangeListener(this);
storageManager = InspectIT.getDefault().getInspectITStorageManager();
storageManager.addStorageChangeListener(this);
updateStorageList(null);
updateDownloadedStorages();
}
/**
* {@inheritDoc}
*/
@Override
public void createPartControl(Composite parent) {
toolkit = new FormToolkit(parent.getDisplay());
createViewToolbar();
mainComposite = new SashForm(parent, SWT.VERTICAL);
GridLayout mainLayout = new GridLayout(1, true);
mainLayout.marginWidth = 0;
mainLayout.marginHeight = 0;
mainComposite.setLayout(mainLayout);
mainForm = toolkit.createForm(mainComposite);
mainForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout lauout = new GridLayout(1, true);
lauout.marginWidth = 0;
lauout.marginHeight = 0;
mainForm.getBody().setLayout(lauout);
toolkit.decorateFormHeading(mainForm);
createHeadClient();
upperComposite = toolkit.createComposite(mainForm.getBody());
lauout = new GridLayout(1, true);
lauout.marginHeight = 0;
upperComposite.setLayout(lauout);
upperComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
int borderStyle = toolkit.getBorderStyle();
toolkit.setBorderStyle(SWT.NULL);
Tree tree = toolkit.createTree(upperComposite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
toolkit.setBorderStyle(borderStyle);
treeViewer = new TreeViewer(tree);
treeViewer.setContentProvider(new StorageManagerTreeContentProvider());
treeViewer.setLabelProvider(new StorageManagerTreeLabelProvider());
// treeViewer.setComparator(new ServerViewComparator());
treeViewer.setComparator(new ViewerComparator() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if ((e1 instanceof GroupedLabelsComposite) && (e2 instanceof GroupedLabelsComposite)) {
return ObjectUtils.compare((GroupedLabelsComposite) e1, (GroupedLabelsComposite) e2);
} else if ((e1 instanceof Component) && (e2 instanceof Component)) {
return ((Component) e1).getName().compareToIgnoreCase(((Component) e2).getName());
}
return super.compare(viewer, e1, e2);
}
});
treeViewer.addFilter(treeFilter);
treeViewer.addFilter(filterStorageComposite.getFilter());
treeViewer.getTree().setVisible(false);
ColumnViewerToolTipSupport.enableFor(treeViewer, ToolTip.NO_RECREATE);
storagePropertyForm = new StorageDataPropertyForm(mainComposite);
storagePropertyForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
treeViewer.addSelectionChangedListener(storagePropertyForm);
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
StructuredSelection structuredSelection = (StructuredSelection) event.getSelection();
if (structuredSelection.getFirstElement() instanceof StorageLeaf) {
lastSelectedLeaf = (StorageLeaf) structuredSelection.getFirstElement();
} else if (structuredSelection.getFirstElement() instanceof LocalStorageLeaf) {
lastSelectedLocalStorageLeaf = (LocalStorageLeaf) structuredSelection.getFirstElement();
}
}
});
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
updateViewToolbar();
}
});
treeViewer.addDoubleClickListener(new DoubleClickListener());
MenuManager menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
getSite().registerContextMenu(MENU_ID, menuManager, treeViewer);
Control control = treeViewer.getControl();
Menu menu = menuManager.createContextMenu(control);
control.setMenu(menu);
mainComposite.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
int width = mainComposite.getBounds().width;
int height = mainComposite.getBounds().height;
if ((width > height) && verticaLayout) {
verticaLayout = false;
mainComposite.setOrientation(SWT.HORIZONTAL);
} else if ((width < height) && !verticaLayout) {
verticaLayout = true;
mainComposite.setOrientation(SWT.VERTICAL);
}
mainComposite.layout();
}
});
updateFormBody();
updateViewToolbar();
mainComposite.setWeights(new int[] { 2, 3 });
getSite().setSelectionProvider(treeViewer);
}
/**
* Creates the head client for form.
*/
private void createHeadClient() {
Composite headClient = new Composite(mainForm.getHead(), SWT.NONE);
GridLayout gl = new GridLayout(3, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
headClient.setLayout(gl);
new Label(headClient, SWT.NONE).setText("Show available:");
remoteStorageSelection = new Button(headClient, SWT.RADIO);
remoteStorageSelection.setText("Online");
remoteStorageSelection.setSelection(true);
localStorageSelection = new Button(headClient, SWT.RADIO);
localStorageSelection.setText("Local");
SelectionAdapter listener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateViewToolbar();
updateFormBody();
}
};
remoteStorageSelection.addSelectionListener(listener);
localStorageSelection.addSelectionListener(listener);
// filter composite
filterStorageComposite = new FilterStorageComposite(headClient, SWT.NONE);
filterStorageComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
mainForm.setHeadClient(headClient);
}
/**
* Creates the view tool-bar.
*/
private void createViewToolbar() {
IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
toolBarManager.add(new ShowPropertiesAction());
MenuAction filterMenuAction = new MenuAction();
filterMenuAction.setText("Group and Filter");
filterMenuAction.setImageDescriptor(InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_FILTER));
groupByLabelMenu = new MenuManager("Group Storages By");
filterMenuAction.addContributionItem(groupByLabelMenu);
filterByRepositoryMenu = new MenuManager("Filter By Repository");
filterMenuAction.addContributionItem(filterByRepositoryMenu);
filterByStateMenu = new MenuManager("Filter By Storage State");
filterByStateMenu.add(new FilterStatesAction("Writable", StorageState.OPENED));
filterByStateMenu.add(new FilterStatesAction("Recording", StorageState.RECORDING));
filterByStateMenu.add(new FilterStatesAction("Readable", StorageState.CLOSED));
filterMenuAction.addContributionItem(filterByStateMenu);
toolBarManager.add(filterMenuAction);
toolBarManager.add(new Separator());
}
/**
* Updates the storage list for all {@link CmrRepositoryDefinition}.
*
* @param jobListener
* the listener.
*/
private void updateStorageList(IJobChangeListener jobListener) {
Job updateStorageListJob = new Job("Update Storages") {
@Override
protected IStatus run(IProgressMonitor monitor) {
storageRepositoryMap.clear();
for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryManager.getCmrRepositoryDefinitions()) {
boolean canUpdate = false;
if (cmrRepositoryDefinition.getOnlineStatus() == OnlineStatus.ONLINE) {
canUpdate = true;
} else {
OnlineStatus cachedStatus = cachedOnlineStatus.get(cmrRepositoryDefinition);
if (OnlineStatus.ONLINE.equals(cachedStatus)) {
canUpdate = true;
}
}
if (canUpdate) {
try {
List<StorageData> storages = cmrRepositoryDefinition.getStorageService().getExistingStorages();
for (StorageData storage : storages) {
storageRepositoryMap.put(storage, cmrRepositoryDefinition);
}
} catch (Exception e) {
continue;
}
}
}
return Status.OK_STATUS;
}
};
if (null != jobListener) {
updateStorageListJob.addJobChangeListener(jobListener);
}
updateStorageListJob.schedule();
}
/**
* Updates the storage list only for provided {@link CmrRepositoryDefinition}.
*
* @param cmrRepositoryDefinition
* {@link CmrRepositoryDefinition}
* @param removeOnly
* If set to true, no storages will be loaded from the CMR.
* @param jobListener
* the job listener.
*/
private void updateStorageList(final CmrRepositoryDefinition cmrRepositoryDefinition, final boolean removeOnly, IJobChangeListener jobListener) {
Job updateStorageListJob = new Job("Updating Storages") {
@Override
protected IStatus run(IProgressMonitor monitor) {
while (storageRepositoryMap.values().remove(cmrRepositoryDefinition)) {
continue;
}
if (!removeOnly) {
boolean canUpdate = false;
if (cmrRepositoryDefinition.getOnlineStatus() == OnlineStatus.ONLINE) {
canUpdate = true;
} else {
OnlineStatus cachedStatus = cachedOnlineStatus.get(cmrRepositoryDefinition);
if (OnlineStatus.ONLINE.equals(cachedStatus)) {
canUpdate = true;
}
}
if (canUpdate) {
List<StorageData> storages = cmrRepositoryDefinition.getStorageService().getExistingStorages();
for (StorageData storage : storages) {
storageRepositoryMap.put(storage, cmrRepositoryDefinition);
}
}
}
return Status.OK_STATUS;
}
};
if (null != jobListener) {
updateStorageListJob.addJobChangeListener(jobListener);
}
updateStorageListJob.schedule();
}
/**
* Updates the list of downloaded storages.
*/
private void updateDownloadedStorages() {
downloadedStorages.clear();
downloadedStorages.addAll(InspectIT.getDefault().getInspectITStorageManager().getDownloadedStorages());
}
/**
* Updates the form body.
*/
private void updateFormBody() {
clearFormBody();
if (remoteStorageSelection.getSelection()) {
if (!storageRepositoryMap.isEmpty()) {
treeViewer.getTree().setVisible(true);
treeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
treeViewer.setInput(new StorageTreeModelManager(storageRepositoryMap, orderingLabelType));
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if ((null != lastSelectedLeaf) && storageRepositoryMap.keySet().contains(lastSelectedLeaf.getStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLeaf);
treeViewer.setSelection(ss, true);
}
filterStorageComposite.setEnabled(true);
} else {
displayMessage("No storage information available on currently available CMR repositories.", Display.getDefault().getSystemImage(SWT.ICON_INFORMATION));
filterStorageComposite.setEnabled(false);
}
} else {
if (!downloadedStorages.isEmpty()) {
treeViewer.getTree().setVisible(true);
treeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
treeViewer.setInput(new LocalStorageTreeModelManager(downloadedStorages, orderingLabelType));
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if ((null != lastSelectedLocalStorageLeaf) && downloadedStorages.contains(lastSelectedLocalStorageLeaf.getLocalStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLocalStorageLeaf);
treeViewer.setSelection(ss, true);
}
filterStorageComposite.setEnabled(true);
} else {
displayMessage("No downloaded storage is available on the local machine.", Display.getDefault().getSystemImage(SWT.ICON_INFORMATION));
filterStorageComposite.setEnabled(false);
}
}
upperComposite.layout();
}
/**
* Clears the look of the forms body.
*/
private void clearFormBody() {
if ((cmrMessageComposite != null) && !cmrMessageComposite.isDisposed()) {
cmrMessageComposite.dispose();
}
treeViewer.setInput(Collections.emptyList());
treeViewer.getTree().setVisible(false);
treeViewer.getTree().setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
}
/**
* Displays the message on the provided composite.
*
* @param text
* Text of message.
* @param image
* Image to show.
*/
private void displayMessage(String text, Image image) {
if ((null == cmrMessageComposite) || cmrMessageComposite.isDisposed()) {
cmrMessageComposite = toolkit.createComposite(upperComposite);
} else {
for (Control c : cmrMessageComposite.getChildren()) {
if (!c.isDisposed()) {
c.dispose();
}
}
}
cmrMessageComposite.setLayout(new GridLayout(2, false));
cmrMessageComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
toolkit.createLabel(cmrMessageComposite, null).setImage(image);
toolkit.createLabel(cmrMessageComposite, text, SWT.WRAP).setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
}
/**
* Updates the view tool-bar.
*/
private void updateViewToolbar() {
boolean remoteStoragesShown = remoteStorageSelection.getSelection();
// filter by repository visible only when remote storages are displayed
filterByRepositoryMenu.removeAll();
for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryManager.getCmrRepositoryDefinitions()) {
filterByRepositoryMenu.add(new FilterRepositoriesAction(cmrRepositoryDefinition));
}
filterByRepositoryMenu.getParent().update(false);
filterByRepositoryMenu.setVisible(remoteStoragesShown);
// filter by state is not visible with downloaded storages displayed
filterByStateMenu.setVisible(remoteStoragesShown);
// group by label
Set<AbstractStorageLabelType<?>> availableLabelTypes = new HashSet<>();
if (remoteStoragesShown) {
for (StorageData storageData : storageRepositoryMap.keySet()) {
for (AbstractStorageLabel<?> label : storageData.getLabelList()) {
availableLabelTypes.add(label.getStorageLabelType());
}
}
} else {
for (LocalStorageData localStorageData : downloadedStorages) {
for (AbstractStorageLabel<?> label : localStorageData.getLabelList()) {
availableLabelTypes.add(label.getStorageLabelType());
}
}
}
groupByLabelMenu.removeAll();
if (remoteStoragesShown) {
groupByLabelMenu.add(new LabelOrderAction("CMR Repository", InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_SERVER_ONLINE_SMALL), null, null == orderingLabelType));
} else {
groupByLabelMenu.add(new LabelOrderAction("None", InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_STORAGE_DOWNLOADED), null, null == orderingLabelType));
}
for (AbstractStorageLabelType<?> labelType : availableLabelTypes) {
if (labelType.isGroupingEnabled()) {
groupByLabelMenu.add(
new LabelOrderAction(TextFormatter.getLabelName(labelType), ImageFormatter.getImageDescriptorForLabel(labelType), labelType, ObjectUtils.equals(labelType, orderingLabelType)));
}
}
}
/**
* Performs update.
*
* @param updateStorageList
* If the update should go to the CMRs for an updated storage list.
*/
private void performUpdate(final boolean updateStorageList) {
updateDownloadedStorages();
if (updateStorageList) {
updateStorageList(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
mainForm.setBusy(true);
updateFormBody();
updateViewToolbar();
mainForm.setBusy(false);
mainForm.layout();
}
}, mainForm);
}
});
} else {
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
mainForm.setBusy(true);
updateFormBody();
updateViewToolbar();
mainForm.setBusy(false);
mainForm.layout();
}
}, mainForm);
}
}
/**
* {@inheritDoc}
*/
@Override
public void setFocus() {
if (treeViewer.getTree().isVisible()) {
treeViewer.getTree().setFocus();
} else {
mainForm.setFocus();
}
}
/**
* {@inheritDoc}
*/
@Override
public void repositoryOnlineStatusUpdated(CmrRepositoryDefinition repositoryDefinition, OnlineStatus oldStatus, OnlineStatus newStatus) {
if (newStatus == OnlineStatus.ONLINE) {
OnlineStatus cachedStatus = cachedOnlineStatus.get(repositoryDefinition);
if ((null == cachedStatus) || OnlineStatus.OFFLINE.equals(cachedStatus) || OnlineStatus.UNKNOWN.equals(cachedStatus)) {
updateStorageList(repositoryDefinition, false, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
updateFormBody();
}
}, mainForm);
}
});
}
cachedOnlineStatus.put(repositoryDefinition, newStatus);
} else if (newStatus == OnlineStatus.OFFLINE) {
OnlineStatus cachedStatus = cachedOnlineStatus.get(repositoryDefinition);
if ((null == cachedStatus) || OnlineStatus.ONLINE.equals(cachedStatus)) {
updateStorageList(repositoryDefinition, true, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
updateFormBody();
}
}, mainForm);
}
});
}
cachedOnlineStatus.put(repositoryDefinition, newStatus);
}
}
/**
* {@inheritDoc}
*/
@Override
public void repositoryAdded(CmrRepositoryDefinition cmrRepositoryDefinition) {
cachedOnlineStatus.put(cmrRepositoryDefinition, cmrRepositoryDefinition.getOnlineStatus());
updateStorageList(cmrRepositoryDefinition, false, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
performUpdate(false);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void repositoryRemoved(CmrRepositoryDefinition cmrRepositoryDefinition) {
cachedOnlineStatus.remove(cmrRepositoryDefinition);
updateStorageList(cmrRepositoryDefinition, true, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
performUpdate(false);
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void repositoryDataUpdated(CmrRepositoryDefinition cmrRepositoryDefinition) {
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
updateFormBody();
updateViewToolbar();
}
}, mainForm);
}
/**
* {@inheritDoc}
*/
@Override
public void repositoryAgentDeleted(CmrRepositoryDefinition cmrRepositoryDefinition, PlatformIdent agent) {
}
/**
* {@inheritDoc}
*/
@Override
public void refresh() {
performUpdate(true);
}
/**
* {@inheritDoc}
*/
@Override
public boolean canRefresh() {
return !storageRepositoryMap.isEmpty() || !cmrRepositoryManager.getCmrRepositoryDefinitions().isEmpty();
}
/**
* Refreshes the view, only by refreshing the storages on the given repository.
*
* @param cmrRepositoryDefinition
* Repository to update storages for.
*/
public void refresh(CmrRepositoryDefinition cmrRepositoryDefinition) {
updateStorageList(cmrRepositoryDefinition, false, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
performUpdate(false);
}
});
}
/**
* Show or hides properties.
*
* @param show
* Should properties be shown.
*/
public void setShowProperties(boolean show) {
if (show) {
StructuredSelection selection = (StructuredSelection) treeViewer.getSelection();
if (!selection.isEmpty()) {
if (selection.getFirstElement() instanceof StorageLeaf) {
StorageLeaf storageLeaf = ((StorageLeaf) selection.getFirstElement());
storagePropertyForm = new StorageDataPropertyForm(mainComposite, storageLeaf);
storagePropertyForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
} else if (selection.getFirstElement() instanceof LocalStorageLeaf) {
IStorageData storageData = ((LocalStorageLeaf) selection.getFirstElement()).getLocalStorageData();
storagePropertyForm = new StorageDataPropertyForm(mainComposite, null, storageData);
storagePropertyForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
} else {
storagePropertyForm = new StorageDataPropertyForm(mainComposite);
storagePropertyForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
}
treeViewer.addSelectionChangedListener(storagePropertyForm);
mainComposite.setWeights(new int[] { 2, 3 });
mainComposite.layout();
} else {
if ((null != storagePropertyForm) && !storagePropertyForm.isDisposed()) {
treeViewer.removeSelectionChangedListener(storagePropertyForm);
storagePropertyForm.dispose();
storagePropertyForm = null; // NOPMD
}
mainComposite.setWeights(new int[] { 1 });
mainComposite.layout();
}
}
/**
* Performs update of the view, without getting data from CMR.
*/
public void refreshWithoutCmrCall() {
performUpdate(false);
}
/**
* {@inheritDoc}
*/
@Override
public void storageDataUpdated(IStorageData storageData) {
CmrRepositoryDefinition repositoryToUpdate = storageRepositoryMap.get(storageData);
if (null != repositoryToUpdate) {
refresh(repositoryToUpdate);
}
}
/**
* {@inheritDoc}
*/
@Override
public void storageRemotelyDeleted(IStorageData storageData) {
for (Iterator<Entry<StorageData, CmrRepositoryDefinition>> it = storageRepositoryMap.entrySet().iterator(); it.hasNext();) {
if (Objects.equals(it.next().getKey().getId(), storageData.getId())) {
it.remove();
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
if (remoteStorageSelection.getSelection()) {
refreshWithoutCmrCall();
}
}
}, remoteStorageSelection);
break;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void storageLocallyDeleted(IStorageData storageData) {
for (Iterator<LocalStorageData> it = downloadedStorages.iterator(); it.hasNext();) {
if (Objects.equals(it.next().getId(), storageData.getId())) {
it.remove();
SafeExecutor.asyncExec(new Runnable() {
@Override
public void run() {
if (localStorageSelection.getSelection()) {
refreshWithoutCmrCall();
}
}
}, localStorageSelection);
break;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
cmrRepositoryManager.removeCmrRepositoryChangeListener(this);
storageManager.removeStorageChangeListener(this);
super.dispose();
}
/**
* Filter for the tree.
*
* @author Ivan Senic
*
*/
private static class TreeFilter extends ViewerFilter {
/**
* Set of excluded repositories.
*/
private final Set<CmrRepositoryDefinition> filteredRespositories = new HashSet<>();
/**
* Set of excluded states.
*/
private final Set<StorageState> filteredStates = new HashSet<>();
/**
* {@inheritDoc}
*/
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof StorageLeaf) {
StorageLeaf storageLeaf = (StorageLeaf) element;
if (filteredRespositories.contains(storageLeaf.getCmrRepositoryDefinition())) {
return false;
}
if (filteredStates.contains(storageLeaf.getStorageData().getState())) {
return false;
}
}
return true;
}
/**
* @return the filteredRespositories
*/
public Set<CmrRepositoryDefinition> getFilteredRespositories() {
return filteredRespositories;
}
/**
* @return the filteredStates
*/
public Set<StorageState> getFilteredStates() {
return filteredStates;
}
}
/**
* Action for selecting the grouping of storages.
*
* @author Ivan Senic
*
*/
private class LabelOrderAction extends Action {
/**
* Label type to group.
*/
private final AbstractStorageLabelType<?> labelType;
/**
* Constructor.
*
* @param name
* Name of action.
* @param imgDescriptor
* {@link ImageDescriptor}.
* @param labelType
* Label type to represent. Null for default settings.
* @param isChecked
* Should be checked.
*/
public LabelOrderAction(String name, ImageDescriptor imgDescriptor, AbstractStorageLabelType<?> labelType, boolean isChecked) {
super(name, IAction.AS_RADIO_BUTTON);
this.labelType = labelType;
setChecked(isChecked);
setImageDescriptor(imgDescriptor);
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
if (isChecked()) {
orderingLabelType = labelType;
updateFormBody();
}
}
}
/**
* Filter by storage repository action.
*
* @author Ivan Senic
*
*/
private class FilterRepositoriesAction extends Action {
/**
* Cmr to exclude/include.
*/
private final CmrRepositoryDefinition cmrRepositoryDefinition;
/**
* @param cmrRepositoryDefinition
* Cmr to exclude/include.
*/
public FilterRepositoriesAction(CmrRepositoryDefinition cmrRepositoryDefinition) {
super();
this.cmrRepositoryDefinition = cmrRepositoryDefinition;
setText(cmrRepositoryDefinition.getName());
setChecked(!treeFilter.getFilteredRespositories().contains(cmrRepositoryDefinition));
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
if (isChecked()) {
treeFilter.getFilteredRespositories().remove(cmrRepositoryDefinition);
} else {
treeFilter.getFilteredRespositories().add(cmrRepositoryDefinition);
}
treeViewer.refresh();
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if ((null != lastSelectedLeaf) && storageRepositoryMap.keySet().contains(lastSelectedLeaf.getStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLeaf);
treeViewer.setSelection(ss, true);
}
}
}
/**
* Filter by storage state action.
*
* @author Ivan Senic
*
*/
private class FilterStatesAction extends Action {
/**
* Storage state to exclude/include.
*/
private final StorageState state;
/**
*
* @param text
* Action text.
* @param state
* Storage state to exclude/include.
*/
public FilterStatesAction(String text, StorageState state) {
super();
this.state = state;
setText(text);
setChecked(!treeFilter.getFilteredStates().contains(state));
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
if (isChecked()) {
treeFilter.getFilteredStates().remove(state);
} else {
treeFilter.getFilteredStates().add(state);
}
treeViewer.refresh();
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if ((null != lastSelectedLeaf) && storageRepositoryMap.keySet().contains(lastSelectedLeaf.getStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLeaf);
treeViewer.setSelection(ss, true);
}
}
}
/**
* Action for show hide properties.
*
* @author Ivan Senic
*
*/
private class ShowPropertiesAction extends Action {
/**
* Default constructor.
*/
public ShowPropertiesAction() {
super(null, AS_CHECK_BOX);
setImageDescriptor(InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_PROPERTIES));
setChecked(true);
setToolTipText("Hide Properties");
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
if (isChecked()) {
setShowProperties(true);
setToolTipText("Hide Properties");
} else {
setShowProperties(false);
setToolTipText("Show Properties");
}
};
}
/**
*
* @author Ivan Senic
*
*/
private final class FilterStorageComposite extends FilterComposite {
/**
* String to be filtered.
*/
private String filterString = "";
/**
* Filter.
*/
private final ViewerFilter filter = new ViewerFilter() {
/**
* {@inheritDoc}
*/
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (Objects.equals("", filterString)) {
return true;
} else {
if (element instanceof IStorageDataProvider) {
return select(((IStorageDataProvider) element).getStorageData());
} else if (element instanceof ILocalStorageDataProvider) {
return select(((ILocalStorageDataProvider) element).getLocalStorageData());
}
return true;
}
}
/**
* Does a filter select on {@link StorageData}.
*
* @param storageData
* {@link IStorageData}
* @return True if data in {@link IStorageData} fits the filter string.
*/
private boolean select(IStorageData storageData) {
if (StringUtils.containsIgnoreCase(storageData.getName(), filterString)) {
return true;
}
if (StringUtils.containsIgnoreCase(storageData.getDescription(), filterString)) {
return true;
}
for (AbstractStorageLabel<?> label : storageData.getLabelList()) {
if (StringUtils.containsIgnoreCase(TextFormatter.getLabelValue(label, false), filterString)) {
return true;
}
}
if (storageData instanceof StorageData) {
if (StringUtils.containsIgnoreCase(((StorageData) storageData).getState().toString(), filterString)) {
return true;
}
}
return false;
}
};
/**
* Default constructor.
*
* @param parent
* A widget which will be the parent of the new instance (cannot be null).
* @param style
* The style of widget to construct.
* @see Composite#Composite(Composite, int)
*/
public FilterStorageComposite(Composite parent, int style) {
super(parent, style, "Filter storages");
((GridLayout) getLayout()).marginWidth = 0;
}
/**
* {@inheritDoc}
*/
@Override
protected void executeCancel() {
this.filterString = "";
treeViewer.refresh();
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if (remoteStorageSelection.getSelection()) {
if ((null != lastSelectedLeaf) && storageRepositoryMap.keySet().contains(lastSelectedLeaf.getStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLeaf);
treeViewer.setSelection(ss, true);
}
} else {
if ((null != lastSelectedLocalStorageLeaf) && downloadedStorages.contains(lastSelectedLocalStorageLeaf.getLocalStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLocalStorageLeaf);
treeViewer.setSelection(ss, true);
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected void executeFilter(String filterString) {
this.filterString = filterString;
treeViewer.refresh();
treeViewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);
if (remoteStorageSelection.getSelection()) {
if ((null != lastSelectedLeaf) && storageRepositoryMap.keySet().contains(lastSelectedLeaf.getStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLeaf);
treeViewer.setSelection(ss, true);
}
} else {
if ((null != lastSelectedLocalStorageLeaf) && downloadedStorages.contains(lastSelectedLocalStorageLeaf.getLocalStorageData())) {
StructuredSelection ss = new StructuredSelection(lastSelectedLocalStorageLeaf);
treeViewer.setSelection(ss, true);
}
}
}
/**
* Gets {@link #filter}.
*
* @return {@link #filter}
*/
public ViewerFilter getFilter() {
return filter;
}
}
/**
* Double click listener, that opens the data explorer.
*
* @author Ivan Senic
*
*/
private class DoubleClickListener implements IDoubleClickListener {
/**
* {@inheritDoc}
*/
@Override
public void doubleClick(final DoubleClickEvent event) {
UIJob openDataExplorerJob = new UIJob("Opening Data Explorer..") {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
process();
return Status.OK_STATUS;
}
};
openDataExplorerJob.setUser(true);
openDataExplorerJob.schedule();
}
/**
* Processes the double-click.
*/
private void process() {
StructuredSelection selection = (StructuredSelection) treeViewer.getSelection();
if (selection.getFirstElement() instanceof IStorageDataProvider) {
showStorage((IStorageDataProvider) selection.getFirstElement(), InspectIT.getDefault().getInspectITStorageManager());
} else if (selection.getFirstElement() instanceof ILocalStorageDataProvider) {
showStorage((ILocalStorageDataProvider) selection.getFirstElement(), InspectIT.getDefault().getInspectITStorageManager());
} else {
TreeSelection treeSelection = (TreeSelection) selection;
TreePath path = treeSelection.getPaths()[0];
if (null != path) {
boolean expanded = treeViewer.getExpandedState(path);
if (expanded) {
treeViewer.collapseToLevel(path, 1);
} else {
treeViewer.expandToLevel(path, 1);
}
}
}
}
/**
* Executes show repository command.
*
* @param repositoryDefinition
* Repository to open.
*/
private void executeShowRepositoryCommand(RepositoryDefinition repositoryDefinition) {
try {
IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
Command command = commandService.getCommand(ShowRepositoryHandler.COMMAND);
ExecutionEvent executionEvent = handlerService.createExecutionEvent(command, new Event());
IEvaluationContext context = (IEvaluationContext) executionEvent.getApplicationContext();
context.addVariable(ShowRepositoryHandler.REPOSITORY_DEFINITION, repositoryDefinition);
command.executeWithChecks(executionEvent);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Shows storage from the {@link IStorageDataProvider}.
*
* @param storageDataProvider
* {@link IStorageDataProvider}
* @param storageManager
* {@link InspectITStorageManager}
*/
private void showStorage(IStorageDataProvider storageDataProvider, final InspectITStorageManager storageManager) {
final StorageData storageData = storageDataProvider.getStorageData();
final CmrRepositoryDefinition cmrRepositoryDefinition = storageDataProvider.getCmrRepositoryDefinition();
try {
if (storageManager.isStorageMounted(storageData)) {
// if we already have all data needed, get the repository definition and show it
LocalStorageData localStorageData = storageManager.getLocalDataForStorage(storageData);
RepositoryDefinition repositoryDefinition = storageManager.getStorageRepositoryDefinition(localStorageData);
executeShowRepositoryCommand(repositoryDefinition);
} else if (storageData.getState() == StorageState.CLOSED) {
// if it is closed, mount it first
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
SubMonitor subMonitor = SubMonitor.convert(monitor);
storageManager.mountStorage(storageData, cmrRepositoryDefinition, subMonitor);
monitor.done();
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}
});
LocalStorageData localStorageData = storageManager.getLocalDataForStorage(storageData);
RepositoryDefinition repositoryDefinition = storageManager.getStorageRepositoryDefinition(localStorageData);
executeShowRepositoryCommand(repositoryDefinition);
} else if (storageData.getState() == StorageState.OPENED) {
// if it's in writable state offer user to finalize it and explore it
String dialogMessage = "Storages that are in writable mode can not be explored. Do you want to finalize selected storage first and then open it?";
MessageDialog dialog = new MessageDialog(getSite().getShell(), "Opening Writable Storage", null, dialogMessage, MessageDialog.QUESTION, new String[] { "Yes", "No" }, 0);
if (0 == dialog.open()) {
treeViewer.setSelection(treeViewer.getSelection());
IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
Command command = commandService.getCommand(CloseAndShowStorageHandler.COMMAND);
ExecutionEvent executionEvent = handlerService.createExecutionEvent(command, new Event());
IEvaluationContext context = (IEvaluationContext) executionEvent.getApplicationContext();
context.addVariable(CloseAndShowStorageHandler.STORAGE_DATA_PROVIDER, storageDataProvider);
context.addVariable(ISources.ACTIVE_SITE_NAME, getSite());
try {
command.executeWithChecks(executionEvent);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return;
} else if (storageData.getState() == StorageState.RECORDING) {
// if it is used for recording, just show message
InspectIT.getDefault().createInfoDialog("Selected storage is currently used for recording, it can not be explored.", -1);
}
} catch (InvocationTargetException | InterruptedException e) { // NOPMD
InspectIT.getDefault().createErrorDialog("Exception occurred trying to mount the storage", e, -1);
} catch (SerializationException e) {
String msg = "Data in the remote storage " + storageData + " can not be read with this version of inspectIT.";
if (null != storageData.getCmrVersion()) {
msg += " Version of the CMR where storage was created is " + storageData.getCmrVersion() + ".";
} else {
msg += " Version of the CMR where storage was created is unknown";
}
InspectIT.getDefault().createErrorDialog(msg, e, -1);
} catch (BusinessException | IOException e) {
InspectIT.getDefault().createErrorDialog("Exception occurred trying to display the remote storage", e, -1);
}
}
/**
* Shows storage from the {@link ILocalStorageDataProvider}.
*
* @param localStorageDataProvider
* {@link ILocalStorageDataProvider}
* @param storageManager
* {@link InspectITStorageManager}
*/
private void showStorage(ILocalStorageDataProvider localStorageDataProvider, InspectITStorageManager storageManager) {
LocalStorageData localStorageData = localStorageDataProvider.getLocalStorageData();
try {
if (localStorageData.isFullyDownloaded()) {
StorageRepositoryDefinition storageRepositoryDefinition;
storageRepositoryDefinition = storageManager.getStorageRepositoryDefinition(localStorageData);
executeShowRepositoryCommand(storageRepositoryDefinition);
}
} catch (SerializationException e) {
String msg = "Data in the remote storage " + localStorageData + " can not be read with this version of inspectIT.";
if (null != localStorageData.getCmrVersion()) {
msg += " Version of the CMR where storage was created is " + localStorageData.getCmrVersion() + ".";
} else {
msg += " Version of the CMR where storage was created is unknown";
}
InspectIT.getDefault().createErrorDialog(msg, e, -1);
} catch (BusinessException | IOException e) {
InspectIT.getDefault().createErrorDialog("Exception occurred trying to display the downloaded storage", e, -1);
}
}
}
}