From 9359015968998bce1e84b1e24256aafe28836cd4 Mon Sep 17 00:00:00 2001 From: Cherian Mathew Date: Fri, 16 Oct 2015 16:20:04 +0200 Subject: [PATCH] #5297 Add remoting progress monitoring #5297 Change active seesion variable to a inheritable thread local variable and add relevant tests Add monitered operation #5297 Add post monitor operation callback, Add report text dialog #5297 Add progress monitor client manager #5297 Add file saving to report dialog #5297 Rename polling method --- .../CdmApplicationRemoteConfiguration.java | 9 +- .../session/CdmEntitySessionManager.java | 35 +- .../TransientCdmRepository.java | 9 + .../etaxonomy/taxeditor/io/ImportManager.java | 67 +- .../taxeditor/io/wizard/AbcdImportWizard.java | 6 +- .../taxeditor/model/AbstractUtility.java | 1227 +++++++++-------- .../IPostMoniteredOperationEnabled.java | 24 + .../etaxonomy/taxeditor/store/CdmStore.java | 7 + .../taxeditor/ui/dialog/ReportTextDialog.java | 134 ++ .../util/ProgressMonitorClientManager.java | 102 ++ .../httpinvoker/BaseRemotingTest.java | 20 +- .../httpinvoker/HttpInvokerServicesTest.java | 2 + .../httpinvoker/RemotingSessionAwareTest.java | 25 + .../taxeditor/httpinvoker/TestThread.java | 60 + .../taxeditor/httpinvoker/ThreadedTest.java | 50 + .../service/ProgressMonitorServiceTest.java | 159 +++ .../session/CdmEntitySessionAwareTest.java | 35 +- 17 files changed, 1359 insertions(+), 612 deletions(-) create mode 100644 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/operation/IPostMoniteredOperationEnabled.java create mode 100644 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/ui/dialog/ReportTextDialog.java create mode 100644 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/util/ProgressMonitorClientManager.java create mode 100644 eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/TestThread.java create mode 100644 eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/ThreadedTest.java create mode 100644 eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/service/ProgressMonitorServiceTest.java diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java index 0de5bc0bd..760b71c90 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java @@ -56,6 +56,7 @@ import eu.etaxonomy.cdm.api.service.INameService; import eu.etaxonomy.cdm.api.service.IOccurrenceService; import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService; import eu.etaxonomy.cdm.api.service.IPolytomousKeyService; +import eu.etaxonomy.cdm.api.service.IProgressMonitorService; import eu.etaxonomy.cdm.api.service.IReferenceService; import eu.etaxonomy.cdm.api.service.IService; import eu.etaxonomy.cdm.api.service.ITaxonNodeService; @@ -81,6 +82,7 @@ import eu.etaxonomy.cdm.persistence.hibernate.permission.voter.TaxonBaseVoter; import eu.etaxonomy.cdm.persistence.hibernate.permission.voter.TaxonNodeVoter; import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource; import eu.etaxonomy.taxeditor.service.CachedCommonServiceImpl; +import eu.etaxonomy.taxeditor.service.CdmAuthenticatedHttpInvokerRequestExecutor; import eu.etaxonomy.taxeditor.service.CdmServiceRequestExecutor; import eu.etaxonomy.taxeditor.service.ICachedCommonService; import eu.etaxonomy.taxeditor.service.TermServiceRequestExecutor; @@ -123,7 +125,7 @@ public class CdmApplicationRemoteConfiguration implements ICdmApplicationConfigu this.remoteSource = remoteSource; } - private Object getService(Class clazz, String serviceSuffix, CdmServiceRequestExecutor executor) { + private Object getService(Class clazz, String serviceSuffix, CdmAuthenticatedHttpInvokerRequestExecutor executor) { if(serviceMap.containsKey(clazz)) { return serviceMap.get(clazz); } @@ -361,6 +363,11 @@ public class CdmApplicationRemoteConfiguration implements ICdmApplicationConfigu return (IPolytomousKeyNodeService) getService(IPolytomousKeyNodeService.class, "/remoting/polytomouskeynode.service", new CdmServiceRequestExecutor()); } + @Override + public IProgressMonitorService getProgressMonitorService() { + return (IProgressMonitorService) getService(IProgressMonitorService.class, "/remoting/progressmonitor.service", new CdmAuthenticatedHttpInvokerRequestExecutor()); + } + @Override public IWorkingSetService getWorkingSetService(){ return (IWorkingSetService) getService(IWorkingSetService.class, "/remoting/workingset.service", new CdmServiceRequestExecutor()); diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java index 80bc0caba..5582df777 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java @@ -38,7 +38,9 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { private final List sessionObservers = new ArrayList(); - private ICdmEntitySession activeSession; + //private ICdmEntitySession activeSession; + + private final InheritableThreadLocal tlActiveSession = new InheritableThreadLocal(); private NullSession nullSession; @@ -76,11 +78,12 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { @Override public ICdmEntitySession getActiveSession() { - return activeSession; + return tlActiveSession.get(); } + private void setActiveSession(ICdmEntitySession activeSession) { - this.activeSession = activeSession; + this. tlActiveSession.set(activeSession); notifyObservers(); } @@ -123,18 +126,18 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { */ @Override public T load(T obj, boolean update) { - if(activeSession == null) { + if(tlActiveSession.get() == null) { return obj; } else { - return activeSession.load(obj, update); + return tlActiveSession.get().load(obj, update); } } @Override public void update() { - if(activeSession != null) { - activeSession.update(); + if(tlActiveSession.get() != null) { + tlActiveSession.get().update(); } } @@ -143,10 +146,10 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { */ @Override public T load(T cdmBase, boolean update) { - if(activeSession == null) { + if(tlActiveSession.get() == null) { return cdmBase; } - return activeSession.load(cdmBase, update); + return tlActiveSession.get().load(cdmBase, update); } @@ -155,10 +158,10 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { */ @Override public UpdateResult load(UpdateResult updateResult, boolean update) { - if(activeSession == null) { + if(tlActiveSession.get() == null) { return updateResult; } - return activeSession.load(updateResult, update); + return tlActiveSession.get().load(updateResult, update); } @@ -167,10 +170,10 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { */ @Override public MergeResult load(MergeResult mergeResult, boolean update) { - if(activeSession == null) { + if(tlActiveSession.get() == null) { return mergeResult; } - return activeSession.load(mergeResult, update); + return tlActiveSession.get().load(mergeResult, update); } @@ -179,10 +182,10 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { */ @Override public Collection load(Collection cdmBaseList, boolean update) { - if(activeSession == null) { + if(tlActiveSession.get() == null) { return cdmBaseList; } - return activeSession.load(cdmBaseList, update); + return tlActiveSession.get().load(cdmBaseList, update); } @@ -195,7 +198,7 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { logger.info("No Session connected to owner, nothing to do"); return; } - if(session == activeSession) { + if(session == tlActiveSession.get()) { setActiveSession(null); } ownerSessionMap.remove(owner); diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java index aebdee8f9..2a2caea56 100644 --- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java +++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java @@ -37,6 +37,7 @@ import eu.etaxonomy.cdm.api.service.INameService; import eu.etaxonomy.cdm.api.service.IOccurrenceService; import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService; import eu.etaxonomy.cdm.api.service.IPolytomousKeyService; +import eu.etaxonomy.cdm.api.service.IProgressMonitorService; import eu.etaxonomy.cdm.api.service.IReferenceService; import eu.etaxonomy.cdm.api.service.IService; import eu.etaxonomy.cdm.api.service.ITaxonNodeService; @@ -418,4 +419,12 @@ public class TransientCdmRepository implements ICdmApplicationConfiguration { public IAnnotationService getAnnotationService() { return defaultApplicationConfiguration.getAnnotationService(); } + + /** + * {@inheritDoc} + */ + @Override + public IProgressMonitorService getProgressMonitorService() { + return defaultApplicationConfiguration.getProgressMonitorService(); + } } diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/ImportManager.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/ImportManager.java index 89249cddc..f2dcc0140 100644 --- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/ImportManager.java +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/ImportManager.java @@ -15,6 +15,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.UUID; import org.apache.commons.io.IOUtils; import org.eclipse.core.runtime.Assert; @@ -26,6 +27,7 @@ import org.eclipse.swt.widgets.Display; import eu.etaxonomy.cdm.api.application.CdmApplicationState; import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration; +import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor; import eu.etaxonomy.cdm.io.common.CdmDefaultImport; import eu.etaxonomy.cdm.io.common.IImportConfigurator; import eu.etaxonomy.cdm.io.common.IImportConfigurator.SOURCE_TYPE; @@ -37,8 +39,10 @@ import eu.etaxonomy.cdm.io.service.IIOService; import eu.etaxonomy.cdm.io.specimen.abcd206.in.Abcd206ImportConfigurator; import eu.etaxonomy.cdm.io.specimen.excel.in.SpecimenCdmExcelImportConfigurator; import eu.etaxonomy.cdm.io.tcsxml.in.TcsXmlImportConfigurator; +import eu.etaxonomy.taxeditor.model.AbstractUtility; import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter; import eu.etaxonomy.taxeditor.model.MessagingUtils; +import eu.etaxonomy.taxeditor.operation.IPostMoniteredOperationEnabled; import eu.etaxonomy.taxeditor.store.CdmStore; import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin; @@ -51,7 +55,7 @@ import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin; * @created Sep 11, 2009 * @version 1.0 */ -public class ImportManager extends AbstractIOManager { +public class ImportManager extends AbstractIOManager implements IPostMoniteredOperationEnabled { /** * @param applicationConfiguration @@ -195,6 +199,52 @@ public class ImportManager extends AbstractIOManager { return job; + } + + public void runMoniteredOperation(IImportConfigurator configurator, InputStream is, SOURCE_TYPE type) { + + try { + runMoniteredOperation(configurator, IOUtils.toByteArray(is), type); + } catch (Exception e) { + MessagingUtils.errorDialog("Error importing input stream", + this, + e.getMessage(), + TaxeditorStorePlugin.PLUGIN_ID, + e, + true); + } + + } + + public void runMoniteredOperation(IImportConfigurator configurator, File importFile, SOURCE_TYPE type) { + Path path = Paths.get(importFile.toURI()); + try { + runMoniteredOperation(configurator, Files.readAllBytes(path), type); + } catch (Exception e) { + MessagingUtils.errorDialog("Error importing input stream", + this, + e.getMessage(), + TaxeditorStorePlugin.PLUGIN_ID, + e, + true); + } + + } + + public void runMoniteredOperation(final IImportConfigurator configurator, final byte[] data, final SOURCE_TYPE type) { + IIOService ioService = CdmApplicationState.getIOService(); + final UUID uuid = ioService.monitImportData(configurator, data, type); + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + AbstractUtility.executeMoniteredOperation("Import: " + configurator.getClass().getSimpleName(), + uuid, + 1000, + false, + ImportManager.this); + } + }); + } private IImportConfigurator getConfigurator(TYPE type) { @@ -301,5 +351,20 @@ public class ImportManager extends AbstractIOManager { return (SpecimenCdmExcelImportConfigurator) getConfigurator(TYPE.SpecimenCdmExcel); } + /** + * {@inheritDoc} + */ + @Override + public void postOperation(IRemotingProgressMonitor monitor) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + CdmStore.getContextManager().notifyContextRefresh(); + } + }); + + } + } diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/wizard/AbcdImportWizard.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/wizard/AbcdImportWizard.java index 70bc683ba..4dc3d410c 100644 --- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/wizard/AbcdImportWizard.java +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/io/wizard/AbcdImportWizard.java @@ -16,7 +16,6 @@ import java.io.FileNotFoundException; import java.net.URI; import org.apache.log4j.Logger; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IWorkbench; @@ -66,8 +65,9 @@ public class AbcdImportWizard extends AbstractImportWizardstatusLineManager */ protected static IStatusLineManager statusLineManager; - /** - *

- * closeAll - *

- * - * @return a boolean. - */ - public static boolean closeAll() { - return getActivePage().closeAllEditors(true); - } - - /** - * Close the given editor. - * - * @param editor - * The MultipageTaxonEditor to close. - * @return true on success - */ - public static boolean close(EditorPart editor) { - return getActivePage().closeEditor(editor, true); - } - - /** - *

- * getShell - *

- * - * @return a {@link org.eclipse.swt.widgets.Shell} object. - */ - public static Shell getShell() { - - return TaxeditorStorePlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow().getShell(); - } - - /** - *

- * getActivePage - *

- * - * @return a {@link org.eclipse.ui.IWorkbenchPage} object. - */ - public static IWorkbenchPage getActivePage() { - - return TaxeditorStorePlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow().getActivePage(); - } - - /** - *

- * getActivePart - *

- * - * @return a {@link org.eclipse.ui.IWorkbenchPart} object. - */ - public static IWorkbenchPart getActivePart() { - return getActivePage() != null ? getActivePage().getActivePart() : null; - } - - public static IWorkbench getWorkbench() { - return TaxeditorStorePlugin.getDefault().getWorkbench(); - } - - /** - *

- * getWorkbenchWindow - *

- * - * @return a {@link org.eclipse.jface.window.ApplicationWindow} object. - */ - public static ApplicationWindow getWorkbenchWindow() { - if (getWorkbench().getWorkbenchWindowCount() > 1) { - throw new IllegalStateException("More than one workbench window"); - } - return (ApplicationWindow) getWorkbench().getWorkbenchWindows()[0]; - } - - /** - *

- * showView - *

- * - * @param id - * a {@link java.lang.String} object. - * @return a {@link org.eclipse.ui.IViewPart} object. - */ - public static IViewPart showView(String id) { - try { - return PlatformUI.getWorkbench().getActiveWorkbenchWindow() - .getActivePage() - .showView(id, null, IWorkbenchPage.VIEW_VISIBLE); - } catch (PartInitException e) { - MessagingUtils.messageDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e); - return null; - } - } - - /** - *

- * hideView - *

- * - * @param view - * a {@link org.eclipse.ui.IViewPart} object. - */ - public static void hideView(IViewPart view) { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() - .hideView(view); - } - - /** - *

- * getView - *

- * - * @param id - * a {@link java.lang.String} object. - * @param restore - * a boolean. - * @return a {@link org.eclipse.ui.IViewPart} object. - */ - public static IViewPart getView(String id, boolean restore) { - IViewReference[] references = PlatformUI.getWorkbench() - .getActiveWorkbenchWindow().getActivePage().getViewReferences(); - for (IViewReference reference : references) { - if (reference.getId().equals(id)) { - return reference.getView(restore); - } - } - return null; - } - - /** - *

- * getService - *

- * - * @param api - * a {@link java.lang.Class} object. - * @return a {@link java.lang.Object} object. - */ - public static Object getService(Class api) { - return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api); - } - - /** - *

- * getCurrentTheme - *

- * - * @return a {@link org.eclipse.ui.themes.ITheme} object. - */ - public static ITheme getCurrentTheme() { - IThemeManager themeManager = TaxeditorStorePlugin.getDefault() - .getWorkbench().getThemeManager(); - return themeManager.getCurrentTheme(); - } - - /** - * Fonts registered to the plugin may be obtained with the Eclipse themeing - * functionality. Thus fonts are chooseable by the user via - * Preferences->General->Appearance->Colors and Fonts - * - * @return the FontRegistry for the current theme - */ - public static FontRegistry getFontRegistry() { - return getCurrentTheme().getFontRegistry(); - } - - /** - *

- * getFont - *

- * - * @param symbolicName - * a {@link java.lang.String} object. - * @return a {@link org.eclipse.swt.graphics.Font} object. - */ - public static Font getFont(String symbolicName) { - return getFontRegistry().get(symbolicName); - } - - /** - * Color registered to the plugin may be obtained with the Eclipse themeing - * functionality. Thus colors are editable by the user via - * Preferences->General->Appearance->Colors and Fonts - * - * @return the ColorRegistry for the current theme - */ - public static ColorRegistry getColorRegistry() { - return getCurrentTheme().getColorRegistry(); - } - - /** - *

- * getColor - *

- * - * @param symbolicName - * a {@link java.lang.String} object. - * @return a {@link org.eclipse.swt.graphics.Color} object. - */ - public static Color getColor(String symbolicName) { - return getColorRegistry().get(symbolicName); - } - - /** - *

- * executeOperation - *

- * - * @param operation - * a - * {@link eu.etaxonomy.taxeditor.operation.AbstractPostTaxonOperation} - * object. - * @return a {@link org.eclipse.core.runtime.IStatus} object. - */ - public static IStatus executeOperation(final AbstractPostOperation operation) { - if (getOperationHistory() == null) { - throw new IllegalArgumentException( - "There is no operation history for this context"); - } - - final IAdaptable uiInfoAdapter = WorkspaceUndoUtil - .getUIInfoAdapter(getShell()); - - IRunnableWithProgress runnable = new IRunnableWithProgress() { - - @Override + /** + *

+ * closeAll + *

+ * + * @return a boolean. + */ + public static boolean closeAll() { + return getActivePage().closeAllEditors(true); + } + + /** + * Close the given editor. + * + * @param editor + * The MultipageTaxonEditor to close. + * @return true on success + */ + public static boolean close(EditorPart editor) { + return getActivePage().closeEditor(editor, true); + } + + /** + *

+ * getShell + *

+ * + * @return a {@link org.eclipse.swt.widgets.Shell} object. + */ + public static Shell getShell() { + + return TaxeditorStorePlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getShell(); + } + + /** + *

+ * getActivePage + *

+ * + * @return a {@link org.eclipse.ui.IWorkbenchPage} object. + */ + public static IWorkbenchPage getActivePage() { + + return TaxeditorStorePlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getActivePage(); + } + + /** + *

+ * getActivePart + *

+ * + * @return a {@link org.eclipse.ui.IWorkbenchPart} object. + */ + public static IWorkbenchPart getActivePart() { + return getActivePage() != null ? getActivePage().getActivePart() : null; + } + + public static IWorkbench getWorkbench() { + return TaxeditorStorePlugin.getDefault().getWorkbench(); + } + + /** + *

+ * getWorkbenchWindow + *

+ * + * @return a {@link org.eclipse.jface.window.ApplicationWindow} object. + */ + public static ApplicationWindow getWorkbenchWindow() { + if (getWorkbench().getWorkbenchWindowCount() > 1) { + throw new IllegalStateException("More than one workbench window"); + } + return (ApplicationWindow) getWorkbench().getWorkbenchWindows()[0]; + } + + /** + *

+ * showView + *

+ * + * @param id + * a {@link java.lang.String} object. + * @return a {@link org.eclipse.ui.IViewPart} object. + */ + public static IViewPart showView(String id) { + try { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage() + .showView(id, null, IWorkbenchPage.VIEW_VISIBLE); + } catch (PartInitException e) { + MessagingUtils.messageDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e); + return null; + } + } + + /** + *

+ * hideView + *

+ * + * @param view + * a {@link org.eclipse.ui.IViewPart} object. + */ + public static void hideView(IViewPart view) { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() + .hideView(view); + } + + /** + *

+ * getView + *

+ * + * @param id + * a {@link java.lang.String} object. + * @param restore + * a boolean. + * @return a {@link org.eclipse.ui.IViewPart} object. + */ + public static IViewPart getView(String id, boolean restore) { + IViewReference[] references = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage().getViewReferences(); + for (IViewReference reference : references) { + if (reference.getId().equals(id)) { + return reference.getView(restore); + } + } + return null; + } + + /** + *

+ * getService + *

+ * + * @param api + * a {@link java.lang.Class} object. + * @return a {@link java.lang.Object} object. + */ + public static Object getService(Class api) { + return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api); + } + + /** + *

+ * getCurrentTheme + *

+ * + * @return a {@link org.eclipse.ui.themes.ITheme} object. + */ + public static ITheme getCurrentTheme() { + IThemeManager themeManager = TaxeditorStorePlugin.getDefault() + .getWorkbench().getThemeManager(); + return themeManager.getCurrentTheme(); + } + + /** + * Fonts registered to the plugin may be obtained with the Eclipse themeing + * functionality. Thus fonts are chooseable by the user via + * Preferences->General->Appearance->Colors and Fonts + * + * @return the FontRegistry for the current theme + */ + public static FontRegistry getFontRegistry() { + return getCurrentTheme().getFontRegistry(); + } + + /** + *

+ * getFont + *

+ * + * @param symbolicName + * a {@link java.lang.String} object. + * @return a {@link org.eclipse.swt.graphics.Font} object. + */ + public static Font getFont(String symbolicName) { + return getFontRegistry().get(symbolicName); + } + + /** + * Color registered to the plugin may be obtained with the Eclipse themeing + * functionality. Thus colors are editable by the user via + * Preferences->General->Appearance->Colors and Fonts + * + * @return the ColorRegistry for the current theme + */ + public static ColorRegistry getColorRegistry() { + return getCurrentTheme().getColorRegistry(); + } + + /** + *

+ * getColor + *

+ * + * @param symbolicName + * a {@link java.lang.String} object. + * @return a {@link org.eclipse.swt.graphics.Color} object. + */ + public static Color getColor(String symbolicName) { + return getColorRegistry().get(symbolicName); + } + + /** + *

+ * executeOperation + *

+ * + * @param operation + * a + * {@link eu.etaxonomy.taxeditor.operation.AbstractPostTaxonOperation} + * object. + * @return a {@link org.eclipse.core.runtime.IStatus} object. + */ + public static IStatus executeOperation(final AbstractPostOperation operation) { + if (getOperationHistory() == null) { + throw new IllegalArgumentException( + "There is no operation history for this context"); + } + + final IAdaptable uiInfoAdapter = WorkspaceUndoUtil + .getUIInfoAdapter(getShell()); + + IRunnableWithProgress runnable = new IRunnableWithProgress() { + + @Override public void run(IProgressMonitor monitor) - throws InvocationTargetException, InterruptedException { - String operationlabel = operation.getLabel(); + throws InvocationTargetException, InterruptedException { + String operationlabel = operation.getLabel(); monitor.beginTask(operationlabel, 100); - IStatus status = Status.CANCEL_STATUS; - try { - operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT); - status = getOperationHistory().execute(operation, monitor, - uiInfoAdapter); - } catch (ExecutionException e) { - - MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null); - - } finally { - monitor.done(); - } - - String statusString = status.equals(Status.OK_STATUS) ? "completed" - : "cancelled"; - setStatusLine(operationlabel + " " + statusString + "."); - - } - }; - - try { - runInUI(runnable, null); - } catch (Exception e) { - MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e); - } - - IPostOperationEnabled postOperationEnabled = operation - .getPostOperationEnabled(); - if (postOperationEnabled != null) { - postOperationEnabled.onComplete(); - } - return Status.OK_STATUS; - } - - public static IStatus executeOperation(final AbstractOperation operation, final RemotingCdmHandler handler) { - if (getOperationHistory() == null) { - throw new IllegalArgumentException( - "There is no operation history for this context"); - } - - final IAdaptable uiInfoAdapter = WorkspaceUndoUtil - .getUIInfoAdapter(getShell()); - - IRunnableWithProgress runnable = new IRunnableWithProgress() { - - @Override - public void run(IProgressMonitor monitor) - throws InvocationTargetException, InterruptedException { - String operationlabel = operation.getLabel(); - monitor.beginTask(operationlabel, 100); - IStatus status = Status.CANCEL_STATUS; - try { - operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT); - status = getOperationHistory().execute(operation, monitor, - uiInfoAdapter); - if(handler != null) { - handler.postOperation(status); - } - } catch (ExecutionException e) { - MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null); - } finally { - monitor.done(); - } - - String statusString = status.equals(Status.OK_STATUS) ? "completed" - : "cancelled"; - setStatusLine(operationlabel + " " + statusString + "."); - - } - }; - - try { - runInUI(runnable, null); - } catch (Exception e) { - MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e); - } - - return Status.OK_STATUS; - } - /** - *

- * getOperationHistory - *

- * - * @return a {@link org.eclipse.core.commands.operations.IOperationHistory} - * object. - */ - public static IOperationHistory getOperationHistory() { - return getWorkbench().getOperationSupport().getOperationHistory(); - } - - /** - *

- * setStatusLine - *

- * - * @param message - * a {@link java.lang.String} object. - */ - public static void setStatusLine(final String message) { - Display.getDefault().asyncExec(new Runnable() { - - @Override + IStatus status = Status.CANCEL_STATUS; + try { + operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT); + status = getOperationHistory().execute(operation, monitor, + uiInfoAdapter); + } catch (ExecutionException e) { + + MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null); + + } finally { + monitor.done(); + } + + String statusString = status.equals(Status.OK_STATUS) ? "completed" + : "cancelled"; + setStatusLine(operationlabel + " " + statusString + "."); + + } + }; + + try { + runInUI(runnable, null); + } catch (Exception e) { + MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e); + } + + IPostOperationEnabled postOperationEnabled = operation + .getPostOperationEnabled(); + if (postOperationEnabled != null) { + postOperationEnabled.onComplete(); + } + return Status.OK_STATUS; + } + + public static IStatus executeOperation(final AbstractOperation operation, final RemotingCdmHandler handler) { + if (getOperationHistory() == null) { + throw new IllegalArgumentException( + "There is no operation history for this context"); + } + + final IAdaptable uiInfoAdapter = WorkspaceUndoUtil + .getUIInfoAdapter(getShell()); + + IRunnableWithProgress runnable = new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + String operationlabel = operation.getLabel(); + monitor.beginTask(operationlabel, 100); + IStatus status = Status.CANCEL_STATUS; + try { + operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT); + status = getOperationHistory().execute(operation, monitor, + uiInfoAdapter); + if(handler != null) { + handler.postOperation(status); + } + } catch (ExecutionException e) { + MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null); + } finally { + monitor.done(); + } + + String statusString = status.equals(Status.OK_STATUS) ? "completed" + : "cancelled"; + setStatusLine(operationlabel + " " + statusString + "."); + + } + }; + + try { + runInUI(runnable, null); + } catch (Exception e) { + MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e); + } + + return Status.OK_STATUS; + } + + /** + * Executes a remoting monitored operation + * + * @param label for the operation + * @param uuid of the remoting monitor already started on the server + * @param pollInterval in milliseconds + * @param cancelable flag which determines whether the operation can be cancelled + * @param postOp callback for running post operation logic + * @return + */ + public static IStatus executeMoniteredOperation(final String label, + final UUID uuid, + final int pollInterval, + final boolean cancelable, + final IPostMoniteredOperationEnabled postOp) { + + try { + // get the remoting monitor the first time to make sure that the + // operation is valid + final IProgressMonitorService progressMonitorService = CdmApplicationState.getCurrentAppConfig().getProgressMonitorService(); + final IRemotingProgressMonitor firstRemotingMonitor = progressMonitorService.getRemotingMonitor(uuid); + if(firstRemotingMonitor == null) { + throw new IllegalStateException("Remoting progress monitor is null"); + } + + final ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(getShell()); + IRunnableWithProgress runnable = new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + // run the monitor untilthe operation is finished + IRemotingProgressMonitor remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor(label, uuid, pollInterval, postOp, monitor); + final StringBuilder reportSb = new StringBuilder(); + // collect reports + for(String report : remotingMonitor.getReports()) { + reportSb.append(report); + } + if(!StringUtils.isBlank(reportSb.toString())) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + // display reports with possibility to save + ReportTextDialog dialog = new ReportTextDialog(progressDialog.getShell()); + dialog.setTitle(label + " Report"); + dialog.setReportText(reportSb.toString()); + dialog.open(); + } + }); + } + } + }; + + progressDialog.run(true, cancelable, runnable); + } catch (Exception e) { + MessagingUtils.errorDialog("Error executing operation", + AbstractUtility.class, + "An error occured while executing " + label, + TaxeditorStorePlugin.PLUGIN_ID, + e, + true); + } + + return Status.OK_STATUS; + } + + + /** + *

+ * getOperationHistory + *

+ * + * @return a {@link org.eclipse.core.commands.operations.IOperationHistory} + * object. + */ + public static IOperationHistory getOperationHistory() { + return getWorkbench().getOperationSupport().getOperationHistory(); + } + + /** + *

+ * setStatusLine + *

+ * + * @param message + * a {@link java.lang.String} object. + */ + public static void setStatusLine(final String message) { + Display.getDefault().asyncExec(new Runnable() { + + @Override public void run() { - statusLineManager.setMessage(message); - } - - }); - - } - - /** - *

- * getMonitor - *

- * - * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object. - */ - public static IProgressMonitor getMonitor() { - statusLineManager.setCancelEnabled(false); - return statusLineManager.getProgressMonitor(); - } - - /** - * Starts either the given {@link IProgressMonitor} if it's not - * null or a new {@link NullProgressMonitor}. - * - * @param progressMonitor - * The {@link IProgressMonitor} or null if no - * progress should be reported. - * @param taskName - * The name of the main task. - * @param steps - * The number of steps this task is subdivided into. - * @return The {@link IProgressMonitor}. - */ - public static IProgressMonitor startMainMonitor( - IProgressMonitor progressMonitor, String taskName, int steps) { - IProgressMonitor newMonitor = progressMonitor; - if (newMonitor == null) { - newMonitor = new NullProgressMonitor(); - } - newMonitor.beginTask(taskName == null ? "" : taskName, steps); - newMonitor.subTask(" "); - return newMonitor; - } - - /** - * Creates a {@link SubProgressMonitor} if the given - * {@link IProgressMonitor} is not null and not a - * {@link NullProgressMonitor}. - * - * @param progressMonitor - * The parent {@link IProgressMonitor} of the - * {@link SubProgressMonitor} to be created. - * @param ticks - * The number of steps this subtask is subdivided into. Must be a - * positive number and must not be - * {@link IProgressMonitor#UNKNOWN}. - * @return The {@link IProgressMonitor}. - */ - public static IProgressMonitor getSubProgressMonitor( - IProgressMonitor progressMonitor, int ticks) { - if (progressMonitor == null) { - return new NullProgressMonitor(); - } - if (progressMonitor instanceof NullProgressMonitor) { - return progressMonitor; - } - - return new SubProgressMonitor(progressMonitor, ticks); - } - - /** - * Checks whether the user canceled this operation. If not canceled, the - * given number of steps are declared as done. - * - * @param newMonitor - * a {@link org.eclipse.core.runtime.IProgressMonitor} object. - * @param steps - * a int. - */ - public static void workedChecked(IProgressMonitor newMonitor, int steps) { - // In case the progress monitor was canceled throw an exception. - if (newMonitor.isCanceled()) { - throw new OperationCanceledException(); - } - // Otherwise declare this step as done. - newMonitor.worked(steps); - } - - /** - * Present a progress dialog to the user. This dialog will block the UI - * - * @param runnable - * an implementation of {@link IRunnableWithProgress} - * @throws java.lang.InterruptedException - * if any. - * @throws java.lang.reflect.InvocationTargetException - * if any. - */ - public static void busyCursorWhile(IRunnableWithProgress runnable) - throws InvocationTargetException, InterruptedException { - getProgressService().busyCursorWhile(runnable); - } - - /** - *

- * runInUI - *

- * - * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)} - * @param runnable - * a {@link org.eclipse.jface.operation.IRunnableWithProgress} - * object. - * @param rule - * a {@link org.eclipse.core.runtime.jobs.ISchedulingRule} - * object. - * @throws java.lang.reflect.InvocationTargetException - * if any. - * @throws java.lang.InterruptedException - * if any. - */ - public static void runInUI(IRunnableWithProgress runnable, - ISchedulingRule rule) throws InvocationTargetException, - InterruptedException { - getProgressService().runInUI(getWorkbenchWindow(), runnable, rule); - } - - /** - *

- * run - *

- * - * @param fork - * a boolean. - * @param cancelable - * a boolean. - * @param runnable - * a {@link org.eclipse.jface.operation.IRunnableWithProgress} - * object. - * @throws java.lang.reflect.InvocationTargetException - * if any. - * @throws java.lang.InterruptedException - * if any. - */ - public static void run(boolean fork, boolean cancelable, - IRunnableWithProgress runnable) throws InvocationTargetException, - InterruptedException { - getProgressService().run(fork, cancelable, runnable); - } - - /** - *

- * getProgressService - *

- * - * @return a {@link org.eclipse.ui.progress.IProgressService} object. - */ - public static IProgressService getProgressService() { - IWorkbench workbench = PlatformUI.getWorkbench(); - return workbench.getProgressService(); - } - - /** - *

- * getProgressService2 - *

- * - * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService} - * object. - */ - public static IWorkbenchSiteProgressService getProgressService2() { - return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class); - } - - /** - *

- * getPluginId - *

- * - * @return a {@link java.lang.String} object. - */ - public static String getPluginId() { - return "eu.taxeditor"; - } - - /** - *

- * getActiveEditor - *

- * - * @return a {@link org.eclipse.ui.IEditorPart} object. - */ - public static IEditorPart getActiveEditor() { - return getActivePage() != null ? getActivePage().getActiveEditor() - : null; - } - - /** - *

- * getDetailsView - *

- * - * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart} - * object. - */ - public static DetailsViewPart getDetailsView() { - return (DetailsViewPart) getView(DetailsViewPart.ID, false); - } - - /** - *

- * refreshDetailsViewer - *

- */ - public static void refreshDetailsViewer() { - if (getDetailsView() != null) { - ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh(); - } - } - - /** - *

- * reflowDetailsViewer - *

- */ - public static void reflowDetailsViewer() { - if (getDetailsView() != null) { - ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow(); - } - } - - public static SupplementalDataViewPart getSupplementalDataView() { - return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID, - false); - } - - public static void reflowSupplementalViewer() { - if (getSupplementalDataView() != null) { - ((AbstractCdmDataViewer) getSupplementalDataView().getViewer()) - .reflow(); - } - } + statusLineManager.setMessage(message); + } + + }); + + } + + /** + *

+ * getMonitor + *

+ * + * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object. + */ + public static IProgressMonitor getMonitor() { + statusLineManager.setCancelEnabled(false); + return statusLineManager.getProgressMonitor(); + } + + /** + * Starts either the given {@link IProgressMonitor} if it's not + * null or a new {@link NullProgressMonitor}. + * + * @param progressMonitor + * The {@link IProgressMonitor} or null if no + * progress should be reported. + * @param taskName + * The name of the main task. + * @param steps + * The number of steps this task is subdivided into. + * @return The {@link IProgressMonitor}. + */ + public static IProgressMonitor startMainMonitor( + IProgressMonitor progressMonitor, String taskName, int steps) { + IProgressMonitor newMonitor = progressMonitor; + if (newMonitor == null) { + newMonitor = new NullProgressMonitor(); + } + newMonitor.beginTask(taskName == null ? "" : taskName, steps); + newMonitor.subTask(" "); + return newMonitor; + } + + /** + * Creates a {@link SubProgressMonitor} if the given + * {@link IProgressMonitor} is not null and not a + * {@link NullProgressMonitor}. + * + * @param progressMonitor + * The parent {@link IProgressMonitor} of the + * {@link SubProgressMonitor} to be created. + * @param ticks + * The number of steps this subtask is subdivided into. Must be a + * positive number and must not be + * {@link IProgressMonitor#UNKNOWN}. + * @return The {@link IProgressMonitor}. + */ + public static IProgressMonitor getSubProgressMonitor( + IProgressMonitor progressMonitor, int ticks) { + if (progressMonitor == null) { + return new NullProgressMonitor(); + } + if (progressMonitor instanceof NullProgressMonitor) { + return progressMonitor; + } + + return new SubProgressMonitor(progressMonitor, ticks); + } + + /** + * Checks whether the user canceled this operation. If not canceled, the + * given number of steps are declared as done. + * + * @param newMonitor + * a {@link org.eclipse.core.runtime.IProgressMonitor} object. + * @param steps + * a int. + */ + public static void workedChecked(IProgressMonitor newMonitor, int steps) { + // In case the progress monitor was canceled throw an exception. + if (newMonitor.isCanceled()) { + throw new OperationCanceledException(); + } + // Otherwise declare this step as done. + newMonitor.worked(steps); + } + + /** + * Present a progress dialog to the user. This dialog will block the UI + * + * @param runnable + * an implementation of {@link IRunnableWithProgress} + * @throws java.lang.InterruptedException + * if any. + * @throws java.lang.reflect.InvocationTargetException + * if any. + */ + public static void busyCursorWhile(IRunnableWithProgress runnable) + throws InvocationTargetException, InterruptedException { + getProgressService().busyCursorWhile(runnable); + } + + /** + *

+ * runInUI + *

+ * + * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)} + * @param runnable + * a {@link org.eclipse.jface.operation.IRunnableWithProgress} + * object. + * @param rule + * a {@link org.eclipse.core.runtime.jobs.ISchedulingRule} + * object. + * @throws java.lang.reflect.InvocationTargetException + * if any. + * @throws java.lang.InterruptedException + * if any. + */ + public static void runInUI(IRunnableWithProgress runnable, + ISchedulingRule rule) throws InvocationTargetException, + InterruptedException { + getProgressService().runInUI(getWorkbenchWindow(), runnable, rule); + } + + /** + *

+ * run + *

+ * + * @param fork + * a boolean. + * @param cancelable + * a boolean. + * @param runnable + * a {@link org.eclipse.jface.operation.IRunnableWithProgress} + * object. + * @throws java.lang.reflect.InvocationTargetException + * if any. + * @throws java.lang.InterruptedException + * if any. + */ + public static void run(boolean fork, boolean cancelable, + IRunnableWithProgress runnable) throws InvocationTargetException, + InterruptedException { + getProgressService().run(fork, cancelable, runnable); + } + + /** + *

+ * getProgressService + *

+ * + * @return a {@link org.eclipse.ui.progress.IProgressService} object. + */ + public static IProgressService getProgressService() { + IWorkbench workbench = PlatformUI.getWorkbench(); + return workbench.getProgressService(); + } + + /** + *

+ * getProgressService2 + *

+ * + * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService} + * object. + */ + public static IWorkbenchSiteProgressService getProgressService2() { + return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class); + } + + /** + *

+ * getPluginId + *

+ * + * @return a {@link java.lang.String} object. + */ + public static String getPluginId() { + return "eu.taxeditor"; + } + + /** + *

+ * getActiveEditor + *

+ * + * @return a {@link org.eclipse.ui.IEditorPart} object. + */ + public static IEditorPart getActiveEditor() { + return getActivePage() != null ? getActivePage().getActiveEditor() + : null; + } + + /** + *

+ * getDetailsView + *

+ * + * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart} + * object. + */ + public static DetailsViewPart getDetailsView() { + return (DetailsViewPart) getView(DetailsViewPart.ID, false); + } + + /** + *

+ * refreshDetailsViewer + *

+ */ + public static void refreshDetailsViewer() { + if (getDetailsView() != null) { + ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh(); + } + } + + /** + *

+ * reflowDetailsViewer + *

+ */ + public static void reflowDetailsViewer() { + if (getDetailsView() != null) { + ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow(); + } + } + + public static SupplementalDataViewPart getSupplementalDataView() { + return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID, + false); + } + + public static void reflowSupplementalViewer() { + if (getSupplementalDataView() != null) { + ((AbstractCdmDataViewer) getSupplementalDataView().getViewer()) + .reflow(); + } + } /** diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/operation/IPostMoniteredOperationEnabled.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/operation/IPostMoniteredOperationEnabled.java new file mode 100644 index 000000000..1c15d420f --- /dev/null +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/operation/IPostMoniteredOperationEnabled.java @@ -0,0 +1,24 @@ +// $Id$ +/** +* Copyright (C) 2015 EDIT +* European Distributed Institute of Taxonomy +* http://www.e-taxonomy.eu +* +* The contents of this file are subject to the Mozilla Public License Version 1.1 +* See LICENSE.TXT at the top of this package for the full license terms. +*/ +package eu.etaxonomy.taxeditor.operation; + +import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor; + +/** + * @author cmathew + * @date 22 Oct 2015 + * + */ +public interface IPostMoniteredOperationEnabled { + + + public void postOperation(IRemotingProgressMonitor monitor); + +} diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/store/CdmStore.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/store/CdmStore.java index 8d96d3359..c4d231be2 100644 --- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/store/CdmStore.java +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/store/CdmStore.java @@ -48,6 +48,7 @@ import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; import eu.etaxonomy.taxeditor.session.mock.MockCdmEntitySessionManager; import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin; import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog; +import eu.etaxonomy.taxeditor.util.ProgressMonitorClientManager; import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart; /** @@ -85,6 +86,8 @@ public class CdmStore { private static UseObjectStore useObjectInitializer = new UseObjectStore(); + private static ProgressMonitorClientManager progressMonitorClientManager = new ProgressMonitorClientManager(); + private static CdmStoreConnector job; private Language language; @@ -523,6 +526,10 @@ public class CdmStore { return editorManager; } + public static ProgressMonitorClientManager getProgressMonitorClientManager() { + return progressMonitorClientManager; + } + /* * IMPORT/EXPORT FACTORIES */ diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/ui/dialog/ReportTextDialog.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/ui/dialog/ReportTextDialog.java new file mode 100644 index 000000000..d1cefe66b --- /dev/null +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/ui/dialog/ReportTextDialog.java @@ -0,0 +1,134 @@ +// $Id$ +/** + * Copyright (C) 2015 EDIT + * European Distributed Institute of Taxonomy + * http://www.e-taxonomy.eu + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * See LICENSE.TXT at the top of this package for the full license terms. + */ +package eu.etaxonomy.taxeditor.ui.dialog; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +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.FileDialog; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; + +/** + * @author cmathew + * @date 22 Oct 2015 + * + */ +public class ReportTextDialog extends Dialog { + + private String reportText = ""; + private String title = ""; + /** + * Create the dialog. + * @param parentShell + */ + public ReportTextDialog(Shell parentShell) { + super(parentShell); + } + + /** + * Create contents of the dialog. + * @param parent + */ + @Override + protected Control createDialogArea(final Composite parent) { + Composite container = (Composite) super.createDialogArea(parent); + GridLayout gridLayout = (GridLayout) container.getLayout(); + gridLayout.numColumns = 2; + + StyledText styledText = new StyledText(container, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.BORDER); + styledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + styledText.setText(reportText); + + Button btnSave = new Button(container, SWT.NONE); + btnSave.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog fileDialog = new FileDialog(parent.getShell(), SWT.SAVE); + // Set filter on .txt files + fileDialog.setFilterExtensions(new String[] { "*.txt" }); + // Put in a readable name for the filter + fileDialog.setFilterNames(new String[] { "Textfiles(*.txt)" }); + String fileName = fileDialog.open(); + System.out.println("File Name : " + fileName); + if(fileName != null) { + File file = new File(fileName); + if (file.exists()) { + MessageBox mb = new MessageBox(fileDialog.getParent(), SWT.ICON_WARNING + | SWT.YES | SWT.NO); + mb.setMessage(fileName + " already exists. Do you want to replace it?"); + boolean override = mb.open() == SWT.YES; + if(!override) { + return; + } + } + try { + FileWriter fileWriter = new FileWriter(fileName, false); + fileWriter.write(getReportText()); + fileWriter.close(); + } catch (IOException ioe) { + throw new IllegalStateException(ioe); + } + } + } + }); + btnSave.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); + btnSave.setText("save"); + + return container; + } + + /** + * Create contents of the button bar. + * @param parent + */ + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + + @Override + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText(title); + } + /** + * Return the initial size of the dialog. + */ + @Override + protected Point getInitialSize() { + return new Point(669, 501); + } + + public void setReportText(String text) { + this.reportText = text; + } + + public String getReportText() { + return reportText; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/util/ProgressMonitorClientManager.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/util/ProgressMonitorClientManager.java new file mode 100644 index 000000000..62f00179d --- /dev/null +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/util/ProgressMonitorClientManager.java @@ -0,0 +1,102 @@ +// $Id$ +/** + * Copyright (C) 2015 EDIT + * European Distributed Institute of Taxonomy + * http://www.e-taxonomy.eu + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * See LICENSE.TXT at the top of this package for the full license terms. + */ +package eu.etaxonomy.taxeditor.util; + +import java.text.DecimalFormat; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.eclipse.core.runtime.IProgressMonitor; + +import eu.etaxonomy.cdm.api.application.CdmApplicationState; +import eu.etaxonomy.cdm.api.service.IProgressMonitorService; +import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor; +import eu.etaxonomy.taxeditor.operation.IPostMoniteredOperationEnabled; + +/** + * Manages client side progress monitors + * + * @author cmathew + * @date 23 Oct 2015 + * + */ + +public class ProgressMonitorClientManager { + private static final Logger logger = Logger.getLogger(ProgressMonitorClientManager.class); + + /** + * Polls the progress monitor service for the progress status of a monitor + * corresponding to the given uuid. + * + * + * @param label for the operation + * @param uuid of the remoting monitor already started on the server + * @param pollInterval in milliseconds + * @param cancelable flag which determines whether the operation can be cancelled + * @param postOp callback for running post operation logic + * @param monitor to be updated + * @return a final progress monitor after the operation is completed + * @throws InterruptedException + */ + public IRemotingProgressMonitor pollMonitor(final String label, + final UUID uuid, + final int pollInterval, + final IPostMoniteredOperationEnabled postOp, + IProgressMonitor monitor) throws InterruptedException { + IProgressMonitorService progressMonitorService = CdmApplicationState.getCurrentAppConfig().getProgressMonitorService(); + IRemotingProgressMonitor remotingMonitor = progressMonitorService.getRemotingMonitor(uuid); + try { + final int START_DELAY=10; + // wait about 10 seconds for the remoting monitor to be initialised (i.e. for the begin task method to be called) + for(int i=0;i 0) { + break; + } + } + // if the total work is still not been set then we assume that the + // operation has zero work units + if(remotingMonitor.getTotalWork() == 0) { + throw new InterruptedException("Monitor has zero work units"); + } + // start the client monitor + monitor.beginTask(label, remotingMonitor.getTotalWork()); + logger.info("Work to be done: " + remotingMonitor.getTotalWork()); + int editorTotalWorkDone = 0; + int serverTotalWorkDone = 0; + // loop until the operation is done + while(!(remotingMonitor.isCanceled() || remotingMonitor.isFailed() || remotingMonitor.isDone())) { + // wait for pollInterval, then + // .... retrieve remoting monitor, then + // .... set client monitor info + Thread.sleep(pollInterval); + remotingMonitor = progressMonitorService.getRemotingMonitor(uuid); + serverTotalWorkDone = (int) remotingMonitor.getWorkDone(); + logger.warn("Work done from start: " + serverTotalWorkDone); + String percentage = new DecimalFormat("#.##").format(remotingMonitor.getPercentage()); + monitor.setTaskName(label + " " + percentage + "% done "); + monitor.subTask(remotingMonitor.getSubTask()); + int worked = serverTotalWorkDone - editorTotalWorkDone; + if(worked > 0) { + logger.info("Work done since last check: " + worked); + monitor.worked(worked); + } + editorTotalWorkDone = serverTotalWorkDone; + } + return remotingMonitor; + } finally { + if(postOp != null) { + postOp.postOperation(remotingMonitor); + } + } + } +} diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/BaseRemotingTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/BaseRemotingTest.java index 694d80e57..8a0e18591 100644 --- a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/BaseRemotingTest.java +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/BaseRemotingTest.java @@ -30,7 +30,6 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; -import org.unitils.UnitilsJUnit4; import org.unitils.database.DatabaseUnitils; import org.unitils.database.annotations.Transactional; import org.unitils.database.util.TransactionMode; @@ -61,7 +60,7 @@ import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; */ @Transactional(TransactionMode.DISABLED) @SpringApplicationContext("file:./target/classes/eu/etaxonomy/cdm/testRemotingApplicationContext.xml") -public abstract class BaseRemotingTest extends UnitilsJUnit4 { +public abstract class BaseRemotingTest extends ThreadedTest { private static final Logger logger = Logger.getLogger(BaseRemotingTest.class); @@ -84,6 +83,7 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { private static String user = DEFAULT_USER; private static String password = DEFAULT_PASSWORD; + protected static CDMServer cdmServer; @BeforeClass @@ -136,8 +136,7 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { // Assert.fail("Server failed to start. Reason : " + e.getMessage()); } - logger.info("Emptying all caches (except model cache) "); - //emptyAllCachesExceptModelCache(); + } public static void emptyAllCachesExceptModelCache() { @@ -172,6 +171,12 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { CdmApplicationState.setCurrentDataChangeService(new CdmDataChangeService()); + authenticate(username, password); + + } + + protected static void authenticate(String username, String password) { + //FIXME:Remoting the authentication code should be replaced by a method call which actually // does the authentication in the editor code so that the 'real' authentication can be tested SecurityContextHolder.clearContext(); @@ -183,8 +188,8 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { SecurityContextHolder.setContext(sc); CdmApplicationState.setCurrentSecurityContext(SecurityContextHolder.getContext()); - } + } protected static CdmApplicationRemoteController getRemoteApplicationController() { @@ -211,7 +216,7 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { } protected static CdmEntitySession getActiveSession() { - return (CdmEntitySession) getFieldValueViaReflection(cdmEntitySessionManager, "activeSession"); + return ((InheritableThreadLocal) getFieldValueViaReflection(cdmEntitySessionManager, "tlActiveSession")).get(); } protected static CdmTransientEntityCacher getCacher(ICdmEntitySessionEnabled sessionOwner) { @@ -238,6 +243,9 @@ public abstract class BaseRemotingTest extends UnitilsJUnit4 { } + protected static void authenticateDefaultUser() { + authenticate(user, password); + } } diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/HttpInvokerServicesTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/HttpInvokerServicesTest.java index 8338a2788..f1a6c57a0 100644 --- a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/HttpInvokerServicesTest.java +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/HttpInvokerServicesTest.java @@ -73,4 +73,6 @@ public class HttpInvokerServicesTest extends BaseRemotingTest { testService.waitFor((long) 120000.0); } + + } diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/RemotingSessionAwareTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/RemotingSessionAwareTest.java index 2ef07d2aa..83734e9b0 100644 --- a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/RemotingSessionAwareTest.java +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/RemotingSessionAwareTest.java @@ -12,8 +12,12 @@ package eu.etaxonomy.taxeditor.httpinvoker; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Before; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import eu.etaxonomy.cdm.api.application.CdmApplicationState; +import eu.etaxonomy.cdm.api.service.IUserService; +import eu.etaxonomy.cdm.model.common.User; import eu.etaxonomy.taxeditor.remoting.cache.CdmTransientEntityCacher; import eu.etaxonomy.taxeditor.session.ICdmEntitySession; import eu.etaxonomy.taxeditor.session.MockSessionOwner; @@ -30,6 +34,11 @@ public abstract class RemotingSessionAwareTest extends BaseRemotingTest { protected CdmTransientEntityCacher cacher; protected MockSessionOwner sessionOwner; + private static String extraUsername = "Someone"; + private static String extraPassword = "Password"; + + + private IUserService userService = getRemoteApplicationController().getUserService(); @Before public void initializeSession() { @@ -40,6 +49,16 @@ public abstract class RemotingSessionAwareTest extends BaseRemotingTest { CdmApplicationState.getCurrentDataChangeService().register(sessionOwner); sessionOwner.setCdmEntitySession(cdmEntitySession); cacher = getCacher(sessionOwner); + + UserDetails extraUser = null; + try { + extraUser = userService.loadUserByUsername(extraUsername); + } catch (UsernameNotFoundException unfe) { + User user = User.NewInstance(extraUsername, extraPassword); + userService.createUser(user); + } + + } @After @@ -48,4 +67,10 @@ public abstract class RemotingSessionAwareTest extends BaseRemotingTest { CdmApplicationState.getCurrentDataChangeService().unregister(sessionOwner); logger.info("disposed of mock session owner : " + sessionOwner); } + + + protected static void authenticateExtraUser() { + authenticate(extraUsername, extraPassword); + } + } diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/TestThread.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/TestThread.java new file mode 100644 index 000000000..b70f80293 --- /dev/null +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/TestThread.java @@ -0,0 +1,60 @@ +// $Id$ +/** + * Copyright (C) 2015 EDIT + * European Distributed Institute of Taxonomy + * http://www.e-taxonomy.eu + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * See LICENSE.TXT at the top of this package for the full license terms. + */ +package eu.etaxonomy.taxeditor.httpinvoker; + +/** + * @author cmathew + * @date 16 Oct 2015 + * + */ +public abstract class TestThread extends Thread { + Throwable throwable; + boolean isBlocked = false; + + public TestThread() { + + } + + public TestThread(boolean blocking) { + isBlocked = blocking; + } + /** + * @return the throwable + */ + public Throwable getThrowable() { + return throwable; + } + + /** + * @param throwable the throwable to set + */ + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } + + public void unblock() { + isBlocked = false; + } + + @Override + public final void run() { + try { + while(isBlocked) {}; + doRun(); + } catch(Exception ex) { + throwable = ex; + } catch(AssertionError ae) { + throwable = ae; + } + } + + public abstract void doRun() throws Exception, AssertionError; + +} diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/ThreadedTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/ThreadedTest.java new file mode 100644 index 000000000..bea9a62ec --- /dev/null +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/httpinvoker/ThreadedTest.java @@ -0,0 +1,50 @@ +// $Id$ +/** +* Copyright (C) 2015 EDIT +* European Distributed Institute of Taxonomy +* http://www.e-taxonomy.eu +* +* The contents of this file are subject to the Mozilla Public License Version 1.1 +* See LICENSE.TXT at the top of this package for the full license terms. +*/ +package eu.etaxonomy.taxeditor.httpinvoker; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.After; +import org.unitils.UnitilsJUnit4; + +/** + * @author cmathew + * @date 16 Oct 2015 + * + */ +public abstract class ThreadedTest extends UnitilsJUnit4 { + + private Set threadPool = new HashSet(); + + protected void invokeThread(TestThread thread) { + threadPool.add(thread); + thread.start(); + } + + @After + public void cleanup() throws Throwable { + try { + for(TestThread thread : threadPool) { + if(thread.isAlive()) { + thread.join(); + } + } + + for(TestThread thread : threadPool) { + if(thread.getThrowable() != null) { + throw thread.getThrowable(); + } + } + } finally { + threadPool.clear(); + } + } +} diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/service/ProgressMonitorServiceTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/service/ProgressMonitorServiceTest.java new file mode 100644 index 000000000..89e6da37c --- /dev/null +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/service/ProgressMonitorServiceTest.java @@ -0,0 +1,159 @@ +// $Id$ +/** + * Copyright (C) 2015 EDIT + * European Distributed Institute of Taxonomy + * http://www.e-taxonomy.eu + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * See LICENSE.TXT at the top of this package for the full license terms. + */ +package eu.etaxonomy.taxeditor.service; + +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import eu.etaxonomy.cdm.api.service.IProgressMonitorService; +import eu.etaxonomy.cdm.api.service.ITestService; +import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor; +import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitor; +import eu.etaxonomy.taxeditor.httpinvoker.RemotingSessionAwareTest; +import eu.etaxonomy.taxeditor.operation.IPostMoniteredOperationEnabled; +import eu.etaxonomy.taxeditor.store.CdmStore; + +/** + * @author cmathew + * @date 22 Oct 2015 + * + */ +public class ProgressMonitorServiceTest extends RemotingSessionAwareTest { + + private static final Logger logger = Logger.getLogger(ProgressMonitorServiceTest.class); + + ITestService testService = getRemoteApplicationController().getTestService(); + + IProgressMonitorService progressMonitorService = getRemoteApplicationController().getProgressMonitorService(); + + + + @After + public void revertAuthentication() { + authenticateDefaultUser(); + } + + @Test + public void testMonitLongRunningMethod() throws InterruptedException { + UUID uuid = testService.monitLongRunningMethod(null); + int pollInterval = 1000; + RemotingProgressMonitor expectedMonitor = new RemotingProgressMonitor(); + expectedMonitor.setResult("Success"); + expectedMonitor.addReport("Report"); + expectedMonitor.done(); + IRemotingProgressMonitor remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor("Testing Progress Monitor", + uuid, + pollInterval, + new MockPostMoniteredOperationEnabled(expectedMonitor, uuid), + new NullProgressMonitor()); + } + + @Test + public void testMonitLongRunningMethodByChangingUser() throws InterruptedException { + + IllegalStateException ise = new IllegalStateException("IllegalStateException"); + UUID uuid = testService.monitLongRunningMethod(ise); + authenticateExtraUser(); + IRemotingProgressMonitor monitor = progressMonitorService.getRemotingMonitor(uuid); + Assert.assertNull(monitor); + + } + + @Test + public void testMonitLongRunningMethodWithException() throws InterruptedException { + IllegalStateException ise = new IllegalStateException("IllegalStateException"); + UUID uuid = testService.monitLongRunningMethod(ise); + int pollInterval = 1000; + RemotingProgressMonitor expectedMonitor = new RemotingProgressMonitor(); + expectedMonitor.setResult(ise); + expectedMonitor.setIsFailed(true); + expectedMonitor.done(); + IRemotingProgressMonitor remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor("Testing Progress Monitor", + uuid, + pollInterval, + new MockPostMoniteredOperationEnabled(expectedMonitor, uuid), + new NullProgressMonitor()); + } + + @Test + public void testMonitLongRunningMethodWithCancellation() throws InterruptedException { + IllegalStateException ise = new IllegalStateException("Cancelled Exception"); + final UUID uuid = testService.monitLongRunningMethod(ise); + final int pollInterval = 1000; + final RemotingProgressMonitor expectedMonitor = new RemotingProgressMonitor(); + expectedMonitor.setResult(ise); + expectedMonitor.setCanceled(true); + expectedMonitor.setIsFailed(true); + expectedMonitor.done(); + + Thread thread = new Thread() { + @Override + public void run() { + try { + IRemotingProgressMonitor remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor("Testing Progress Monitor", + uuid, + pollInterval, + null, + new NullProgressMonitor()); + } catch (InterruptedException e) { + + } + } + + }; + thread.start(); + while(!progressMonitorService.isMonitorThreadRunning(uuid)) {} + + progressMonitorService.interrupt(uuid); + + while(progressMonitorService.isMonitorThreadRunning(uuid)) {} + + IRemotingProgressMonitor remotingMonitor = progressMonitorService.getRemotingMonitor(uuid); + new MockPostMoniteredOperationEnabled(expectedMonitor, uuid).postOperation(remotingMonitor); + + } + + + class MockPostMoniteredOperationEnabled implements IPostMoniteredOperationEnabled { + + private RemotingProgressMonitor expectedMonitor; + private UUID monitorUuid; + + public MockPostMoniteredOperationEnabled(RemotingProgressMonitor expectedMonitor, UUID monitorUuid) { + this.expectedMonitor = expectedMonitor; + this.monitorUuid = monitorUuid; + } + /** + * {@inheritDoc} + */ + @Override + public void postOperation(IRemotingProgressMonitor monitor) { + if(expectedMonitor.getResult() instanceof Exception) { + Exception expectedException = (Exception) expectedMonitor.getResult(); + Exception exception = (Exception) monitor.getResult(); + Assert.assertEquals(expectedException.getClass(), expectedException.getClass()); + Assert.assertEquals(expectedException.getMessage(), expectedException.getMessage()); + } else { + Assert.assertEquals(expectedMonitor.getResult(), monitor.getResult()); + } + Assert.assertEquals(expectedMonitor.getReports(), monitor.getReports()); + Assert.assertEquals(expectedMonitor.isCanceled(), monitor.isCanceled()); + Assert.assertEquals(expectedMonitor.isFailed(), monitor.isFailed()); + Assert.assertEquals(expectedMonitor.isDone(), monitor.isDone()); + Assert.assertTrue(!progressMonitorService.isMonitorThreadRunning(monitorUuid)); + } + + } +} diff --git a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionAwareTest.java b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionAwareTest.java index ed9579b1d..88d5b24a7 100644 --- a/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionAwareTest.java +++ b/eu.etaxonomy.taxeditor.test/src/test/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionAwareTest.java @@ -20,7 +20,6 @@ import org.apache.log4j.Logger; import org.hibernate.collection.spi.PersistentCollection; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.unitils.dbunit.annotation.DataSet; @@ -49,6 +48,7 @@ import eu.etaxonomy.cdm.model.description.PolytomousKeyNode; import eu.etaxonomy.cdm.model.media.Rights; import eu.etaxonomy.cdm.model.taxon.Taxon; import eu.etaxonomy.taxeditor.httpinvoker.RemotingSessionAwareTest; +import eu.etaxonomy.taxeditor.httpinvoker.TestThread; /** * @author cmathew @@ -478,29 +478,42 @@ public class CdmEntitySessionAwareTest extends RemotingSessionAwareTest { } } - @Ignore // activate after fixing #5138 + @Test public void updatePerson() { + // Test for #5138 Person person = (Person) CdmApplicationState.getCurrentAppConfig().getAgentService().load(personUuid); - // Note : at this point the contact field in Person (AgentBase) is initialized even though no - // data related to the Contact class exists in the database. person.setFirstname("Me"); CdmApplicationState.getCurrentAppConfig().getAgentService().merge(person); - } - @Ignore // activate after fixing #5138 + @Test public void createPerson() { - + // Test for #5138 Person person = Person.NewInstance(); - //person.setTitleCache("New Person", true); person = (Person) CdmApplicationState.getCurrentAppConfig().getAgentService().merge(person); - //Note : at this point the contact field in Person (AgentBase) is set to null which is - // different behaviour as compared to a load call on an existing Person entity. - // The fact that the contact is null will lead to the all-delete-orphan error. person = (Person) CdmApplicationState.getCurrentAppConfig().getAgentService().load(person.getUuid()); person.setFirstname("Some"); CdmApplicationState.getCurrentAppConfig().getAgentService().merge(person); } + + @Test + public void testThreadLocalActiveSession() throws InterruptedException { + MockSessionOwner so1 = new MockSessionOwner(); + final ICdmEntitySession activeSession = getCdmEntitySessionManager().newSession(so1, true); + TestThread thread = new TestThread(true) { + @Override + public void doRun() throws InterruptedException { + ICdmEntitySession threadLocalActiveSession = getCdmEntitySessionManager().getActiveSession(); + Assert.assertEquals(threadLocalActiveSession, activeSession); + } + }; + invokeThread(thread); + MockSessionOwner so2 = new MockSessionOwner(); + ICdmEntitySession newActiveSession = getCdmEntitySessionManager().newSession(so2, true); + Assert.assertFalse(activeSession.equals(newActiveSession)); + thread.unblock(); + + } } -- 2.34.1