Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2010 BREDEX GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.client.ui.editors; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import javax.persistence.EntityManager; import org.apache.commons.lang.StringUtils; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.DecoratingLabelProvider; import org.eclipse.jface.viewers.DecorationContext; import org.eclipse.jface.viewers.IDecorationContext; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jubula.client.core.businessprocess.TestresultSummaryBP; import org.eclipse.jubula.client.core.model.INodePO; import org.eclipse.jubula.client.core.model.IParameterDetailsPO; import org.eclipse.jubula.client.core.model.ITestResultPO; import org.eclipse.jubula.client.core.model.ITestResultSummaryPO; import org.eclipse.jubula.client.core.model.ITestSuitePO; import org.eclipse.jubula.client.core.model.NodeMaker; import org.eclipse.jubula.client.core.model.PoMaker; import org.eclipse.jubula.client.core.model.TestResultNode; import org.eclipse.jubula.client.core.model.TestResultParameter; import org.eclipse.jubula.client.core.persistence.GeneralStorage; import org.eclipse.jubula.client.core.persistence.NodePM; import org.eclipse.jubula.client.core.persistence.Persistor; import org.eclipse.jubula.client.core.persistence.TestResultPM; import org.eclipse.jubula.client.ui.Plugin; import org.eclipse.jubula.client.ui.constants.CommandIDs; import org.eclipse.jubula.client.ui.constants.Constants; import org.eclipse.jubula.client.ui.constants.ContextHelpIds; import org.eclipse.jubula.client.ui.i18n.Messages; import org.eclipse.jubula.client.ui.provider.contentprovider.TestResultTreeViewContentProvider; import org.eclipse.jubula.client.ui.provider.labelprovider.TestResultTreeViewLabelProvider; import org.eclipse.jubula.client.ui.utils.CommandHelper; import org.eclipse.jubula.client.ui.views.IJBPart; import org.eclipse.jubula.client.ui.views.ITreeViewerContainer; import org.eclipse.jubula.client.ui.views.NonSortedPropertySheetPage; import org.eclipse.jubula.tools.constants.StringConstants; import org.eclipse.jubula.tools.i18n.I18n; import org.eclipse.jubula.tools.objects.event.TestErrorEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.EditorPart; import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Viewer for Test Results associated with a Test Result Summary. * * @author BREDEX GmbH * @created May 17, 2010 */ public class TestResultViewer extends EditorPart implements ISelectionProvider, ITreeViewerContainer, IAdaptable, IJBPart { /** Constant: Editor ID */ public static final String EDITOR_ID = "org.eclipse.jubula.client.ui.editors.TestResultViewer"; //$NON-NLS-1$ /** * ID of the decoration context property for Test Suite end time. * The value of the property is a {@link java.util.Date}. */ public static final String DECORATION_CONTEXT_SUITE_END_TIME_ID = "org.eclipse.jubula.client.ui.editors.TestResultViewer.testSuiteEndTime"; //$NON-NLS-1$ /** the logger */ private static final Logger LOG = LoggerFactory.getLogger(TestResultViewer.class); /** * Operation to gather Test Result information from the database and use * that information to construct a Test Result tree. * * @author BREDEX GmbH * @created May 18, 2010 */ public static final class GenerateTestResultTreeOperation implements IRunnableWithProgress { /** * Reverse lookup for test error event IDs. This is necessary because the * values stored in the database are internationalized, whereas most of the * time we really need the ID itself. */ private static Map<String, String> eventIdReverseLookup = new HashMap<String, String>(); static { //FIXME NLS eventIdReverseLookup.put(I18n.getString(TestErrorEvent.ID.COMPONENT_NOT_FOUND_ERROR), TestErrorEvent.ID.COMPONENT_NOT_FOUND_ERROR); eventIdReverseLookup.put(I18n.getString(TestErrorEvent.ID.CONFIGURATION_ERROR), TestErrorEvent.ID.CONFIGURATION_ERROR); eventIdReverseLookup.put(I18n.getString(TestErrorEvent.ID.IMPL_CLASS_ACTION_ERROR), TestErrorEvent.ID.IMPL_CLASS_ACTION_ERROR); eventIdReverseLookup.put(I18n.getString(TestErrorEvent.ID.VERIFY_FAILED), TestErrorEvent.ID.VERIFY_FAILED); } /** the database ID of the summary for which to generate the tree */ private Long m_summaryId; /** the database ID of the Project associated with the test run */ private Long m_parentProjectId; /** the root node of the created Test Result tree */ private TestResultNode m_rootNode; /** the manager for Test Result entities */ private EntityManager m_session; /** * Constructor * * @param summaryId The database ID of the summary for which to generate the * tree. * @param parentProjectId The database ID of the Project associated * with the test run. * @param session The manager for Test Result entities. The caller is * responsible for managing the session (opening, * closing, etc.). Closing the session before or during * the operation will cause errors. */ public GenerateTestResultTreeOperation(Long summaryId, Long parentProjectId, EntityManager session) { m_summaryId = summaryId; m_parentProjectId = parentProjectId; m_session = session; } /** * {@inheritDoc} */ public void run(IProgressMonitor monitor) { monitor.beginTask("Fetching Test Result data...", //$NON-NLS-1$ IProgressMonitor.UNKNOWN); try { List<ITestResultPO> testResultList = TestResultPM.computeTestResultListForSummary(m_session, m_summaryId); TestResultNode createdNode = null; Stack<TestResultNode> parentNodeStack = new Stack<TestResultNode>(); Set<String> allGuids = new HashSet<String>(); for (ITestResultPO result : testResultList) { allGuids.add(result.getInternalKeywordGuid()); } Map<String, INodePO> guidToNodeMap = NodePM.getNodes(m_parentProjectId, allGuids, GeneralStorage.getInstance().getMasterSession()); for (ITestResultPO result : testResultList) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } int keywordLevel = result.getKeywordLevel(); if (keywordLevel > parentNodeStack.size()) { parentNodeStack.push(createdNode); } else { while (keywordLevel < parentNodeStack.size()) { parentNodeStack.pop(); } } INodePO backingNode = guidToNodeMap.get(result.getInternalKeywordGuid()); final boolean backingNodeExists = backingNode != null; if (!backingNodeExists) { backingNode = generateBackingNode(result); } createdNode = new TestResultNode(backingNodeExists, backingNode, parentNodeStack.isEmpty() ? null : parentNodeStack.peek()); createdNode.setComponentName(result.getComponentName()); createdNode.setComponentType(result.getComponentType()); for (IParameterDetailsPO param : result.getUnmodifiableParameterList()) { createdNode.addParameter(new TestResultParameter(param)); } createdNode.setResult(result.getInternalKeywordStatus(), generateTestErrorEvent(result)); createdNode.setScreenshot(result.getImage()); createdNode.setTimestamp(result.getTimestamp()); if (m_rootNode == null) { m_rootNode = createdNode; } } } finally { monitor.done(); } } /** * * @return the root node of the Test Result tree generated by this * operation. Behavior when this method is called before the * operation is complete is undefined. */ public TestResultNode getRootNode() { return m_rootNode; } /** * Creates and returns a transient keyword suitable for backing the * given result. * * @param result The result for which to generate a backing keyword. * @return a transient keyword that backs the given result, or * <code>null</code> if the keyword type is not recognized. */ private INodePO generateBackingNode(ITestResultPO result) { switch (result.getInternalKeywordType()) { case TestresultSummaryBP.TYPE_TEST_STEP: // FIXME zeb in order to construct a valid Test Step, we // sometimes use whitespace (" ") as a // placeholder. This works so far, as the only // validation is that the string is neither null // nor empty, but this may cause problems in // future. String componentName = !StringUtils.isEmpty(result.getComponentName()) ? result.getComponentName() : StringConstants.SPACE; return NodeMaker.createCapPO(result.getKeywordName(), componentName, result.getInternalComponentType() != null ? result.getInternalComponentType() : StringConstants.SPACE, result.getInternalActionName() != null ? result.getInternalActionName() : StringConstants.SPACE); case TestresultSummaryBP.TYPE_TEST_CASE: return NodeMaker.createSpecTestCasePO(result.getKeywordName(), result.getInternalKeywordGuid()); case TestresultSummaryBP.TYPE_TEST_SUITE: ITestSuitePO backingTestSuite = NodeMaker.createTestSuitePO(result.getKeywordName(), result.getInternalKeywordGuid()); ITestResultSummaryPO summary = GeneralStorage.getInstance().getMasterSession() .find(PoMaker.getTestResultSummaryClass(), m_summaryId); backingTestSuite.setAut(PoMaker.createAUTMainPO(summary.getAutName())); return backingTestSuite; default: return null; } } /** * * @param result The result for which to generate a test error event. * @return a test error event corresponding to the given result, or * <code>null</code> if the given result is not an error result. */ private TestErrorEvent generateTestErrorEvent(ITestResultPO result) { TestErrorEvent errorEvent = null; if (result.getInternalKeywordStatus() == TestResultNode.ERROR) { errorEvent = new TestErrorEvent(eventIdReverseLookup.get(result.getStatusType())); if (result.getStatusDescription() != null) { errorEvent.addProp(TestErrorEvent.Property.DESCRIPTION_KEY, result.getStatusDescription()); } if (result.getActualValue() != null) { errorEvent.addProp(TestErrorEvent.Property.ACTUAL_VALUE_KEY, result.getActualValue()); } if (result.getStatusOperator() != null) { errorEvent.addProp(TestErrorEvent.Property.OPERATOR_KEY, result.getStatusOperator()); } if (result.getExpectedValue() != null) { errorEvent.addProp(TestErrorEvent.Property.PATTERN_KEY, result.getExpectedValue()); } return errorEvent; } return null; } } /** the viewer */ private TreeViewer m_viewer; /** the manager for Test Result entities */ private EntityManager m_session; /** * whether the Test Results loaded in this viewer will be cached in the * master session */ private boolean m_cacheResults; /** * the root node */ private TestResultNode m_testResultRootNode; /** {@inheritDoc} */ public void doSave(IProgressMonitor monitor) { // "Save" not supported. Do nothing. } /** {@inheritDoc} */ public void doSaveAs() { // "Save as" not supported. Do nothing. } /** {@inheritDoc} */ public Object getAdapter(Class key) { if (key.equals(IPropertySheetPage.class)) { return new NonSortedPropertySheetPage(); } return super.getAdapter(key); } /** {@inheritDoc} */ public void init(IEditorSite site, IEditorInput input) throws PartInitException { if (input instanceof TestResultEditorInput) { setSite(site); setInput(input); setPartName(input.getName()); } else { throw new PartInitException(Messages.EditorInitCreateError); } } /** * Generates a Test Result tree and returns the root node of the generated * tree. * * @param summaryId The database ID of the summary for which to generate the * tree. * @param parentProjectId The database ID of the Project associated with * the test run. * @return the root node of the generated Test Result tree. * * @throws InterruptedException if the operation was cancelled by the user. */ private TestResultNode generateTestResult(Long summaryId, Long parentProjectId) throws InterruptedException { IProgressService progressService = (IProgressService) getSite().getService(IProgressService.class); GenerateTestResultTreeOperation operation = new GenerateTestResultTreeOperation(summaryId, parentProjectId, m_cacheResults ? GeneralStorage.getInstance().getMasterSession() : m_session); try { progressService.busyCursorWhile(operation); } catch (InvocationTargetException e) { LOG.error(Messages.ErrorFetchingTestResultInformation + StringConstants.DOT, e); } catch (OperationCanceledException oce) { throw new InterruptedException(); } return operation.getRootNode(); } /** * * {@inheritDoc} */ public boolean isDirty() { return false; } /** * * {@inheritDoc} */ public boolean isSaveAsAllowed() { return false; } /** * {@inheritDoc} */ public void createPartControl(Composite parent) { TestResultEditorInput editorInput = (TestResultEditorInput) getEditorInput(); m_cacheResults = Plugin.getDefault().getPreferenceStore().getBoolean(Constants.PREF_KEY_CACHE_TEST_RESULTS); if (!m_cacheResults) { m_session = Persistor.instance().openSession(); } m_viewer = new TreeViewer(parent); m_viewer.setContentProvider(new TestResultTreeViewContentProvider()); DecoratingLabelProvider labelProvider = new DecoratingLabelProvider(new TestResultTreeViewLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator()); IDecorationContext decorationContext = labelProvider.getDecorationContext(); if (decorationContext instanceof DecorationContext) { ((DecorationContext) decorationContext).putProperty(DECORATION_CONTEXT_SUITE_END_TIME_ID, editorInput.getTestSuiteEndTime()); } m_viewer.setLabelProvider(labelProvider); getSite().setSelectionProvider(m_viewer); createContextMenu(m_viewer); m_viewer.setAutoExpandLevel(2); PlatformUI.getWorkbench().getHelpSystem().setHelp(m_viewer.getControl(), ContextHelpIds.RESULT_TREE_VIEW); try { setTestResultRootNode( generateTestResult(editorInput.getTestResultSummaryId(), editorInput.getParentProjectId())); m_viewer.setInput(new TestResultNode[] { getTestResultRootNode() }); } catch (InterruptedException ie) { // Operation was cancelled by user m_viewer.getControl().dispose(); m_viewer = null; new Label(parent, SWT.NONE).setText(Messages.EditorsOpenEditorOperationCanceled); } } /** * @param viewer the tree viewer */ private void createContextMenu(TreeViewer viewer) { // Create menu manager. MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager mgr) { fillContextMenu(mgr); } }); // Create menu. Control viewerControl = viewer.getControl(); Menu menu = menuMgr.createContextMenu(viewerControl); viewerControl.setMenu(menu); // Register menu for extension. getSite().registerContextMenu(menuMgr, getTreeViewer()); } /** * @param mgr the menu manager */ private void fillContextMenu(IMenuManager mgr) { CommandHelper.createContributionPushItem(mgr, CommandIDs.EXPAND_TREE_ITEM_COMMAND_ID); mgr.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); } /** * * {@inheritDoc} */ public void setFocus() { if (m_viewer != null && !m_viewer.getControl().isDisposed()) { m_viewer.getControl().setFocus(); } } /** * {@inheritDoc} */ public void addSelectionChangedListener(ISelectionChangedListener listener) { m_viewer.addSelectionChangedListener(listener); } /** * {@inheritDoc} */ public ISelection getSelection() { return m_viewer.getSelection(); } /** * {@inheritDoc} */ public void removeSelectionChangedListener(ISelectionChangedListener listener) { m_viewer.removeSelectionChangedListener(listener); } /** * {@inheritDoc} */ public void setSelection(ISelection selection) { m_viewer.setSelection(selection); } /** * {@inheritDoc} */ public TreeViewer getTreeViewer() { return m_viewer; } @Override public void dispose() { super.dispose(); Persistor.instance().dropSession(m_session); } /** * @return the testResultRootNode */ public TestResultNode getTestResultRootNode() { return m_testResultRootNode; } /** * @param testResultRootNode the testResultRootNode to set */ private void setTestResultRootNode(TestResultNode testResultRootNode) { m_testResultRootNode = testResultRootNode; } }