From: Tuukka Lehtonen Date: Thu, 17 Oct 2019 07:52:39 +0000 (+0300) Subject: Rid TypicalPropertyTester of database read transactions X-Git-Tag: v1.43.0~136^2~53 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=55d1e6f63df516019032ebf0c1e9c8c0495a619d;p=simantics%2Fplatform.git Rid TypicalPropertyTester of database read transactions After this, the normal workbench invocations of TypicalPropertyTester no longer perform any database transactions to do their work. DiagramViewer now has built-in support for doing the required queries based on IDiagram hints alone. gitlab #399 Change-Id: I0dcebcc871f72c16d58a932704c16398df9dd900 --- diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/ResourceSetURIs.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/ResourceSetURIs.java new file mode 100644 index 000000000..0cc29e116 --- /dev/null +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/ResourceSetURIs.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2019 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.db.common.request; + +import java.util.Collections; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; + +import gnu.trove.set.hash.THashSet; + +/** + * @author Tuukka Lehtonen + * @since 1.41.0, 1.35.2 + */ +public class ResourceSetURIs extends UnaryRead, Set> { + + public ResourceSetURIs(Set set) { + super(set); + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + if (parameter == null || parameter.isEmpty()) + return Collections.emptySet(); + + Set result = new THashSet(parameter.size()); + for (Resource r : parameter) { + String uri = graph.getPossibleURI(r); + if (uri != null) + result.add(uri); + } + + return result; + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TypeURIs.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TypeURIs.java new file mode 100644 index 000000000..bc8222bf8 --- /dev/null +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TypeURIs.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2019 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.db.common.request; + +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; + +/** + * @author Tuukka Lehtonen + * @since 1.41.0, 1.35.2 + */ +public class TypeURIs extends ResourceRead> { + + public TypeURIs(Resource r) { + super(r); + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + Set types = graph.getTypes(resource); + return graph.syncRequest(new ResourceSetURIs(types)); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/DiagramModelHints.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/DiagramModelHints.java index e410edb2a..84a25f2de 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/DiagramModelHints.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/DiagramModelHints.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,9 +8,12 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - gitlab #399 *******************************************************************************/ package org.simantics.diagram.ui; +import java.util.Set; + import org.simantics.db.Resource; import org.simantics.db.UndoContext; import org.simantics.db.common.ResourceArray; @@ -40,6 +43,29 @@ public class DiagramModelHints { public static final Key KEY_DIAGRAM_RESOURCE_ARRAY = new KeyOf(ResourceArray.class, "DIAGRAM_RESOURCE_ARRAY"); + /** + * Holds a value of Set which should contain the type {@link Resource} + * URIs of all the types of the diagram resource. This allows doing + * type-checking for the diagram based on pure string instead of having to do + * database transactions to check types. + */ + public static final Key KEY_DIAGRAM_RESOURCE_TYPE_URIS = new KeyOf(Set.class, "DIAGRAM_RESOURCE_TYPE_URIS"); + + /** + * Holds a value of Set which should contain the type {@link Resource} + * URIs of all the types of the composite resource mapped to the diagram + * resource. This allows doing type-checking for the diagram based on pure + * string instead of having to do database transactions to check types. + */ + public static final Key KEY_MAPPED_COMPOSITE_RESOURCE_TYPE_URIS = new KeyOf(Set.class, "MAPPED_DIAGRAM_COMPOSITE_RESOURCE_TYPE_URIS"); + + /** + * Set to the object value if the current diagram editor has a single + * statement/object for the {@link ModelingResources#URIs#HasDiagramSource} + * relation. + */ + public static final Key KEY_HAS_DIAGRAM_SOURCE = new KeyOf(Resource.class, "MOD.HasDiagramSource"); + /** * A hint for defining and extra pass for loading/initializing an element * after the current pass. It is possible to request for infinitely many diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramViewer.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramViewer.java index e773a7a63..a0f504030 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramViewer.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramViewer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,7 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation - * Semantum Oy - issue #4384 + * Semantum Oy - issue #4384, gitlab #399 *******************************************************************************/ package org.simantics.modeling.ui.diagramEditor; @@ -41,9 +41,11 @@ import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.WriteGraph; import org.simantics.db.common.primitiverequest.PossibleAdapter; +import org.simantics.db.common.primitiverequest.PossibleObject; import org.simantics.db.common.procedure.adapter.ListenerDelegate; import org.simantics.db.common.procedure.adapter.ListenerSupport; import org.simantics.db.common.request.ParametrizedRead; +import org.simantics.db.common.request.TypeURIs; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.CommonDBUtils; import org.simantics.db.common.utils.TagUtil; @@ -104,6 +106,7 @@ import org.simantics.g2d.diagram.participant.ZOrderHandler; import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor; import org.simantics.g2d.element.ElementClassProviders; import org.simantics.g2d.element.ElementClasses; +import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.IElementClassProvider; import org.simantics.g2d.element.handler.impl.StaticObjectAdapter; @@ -184,7 +187,7 @@ public class DiagramViewer void doSetTitleToolTip(String name); } - public static final String DIAGRAMMING_CONTEXT = "org.simantics.modeling.ui.diagramming"; //$NON-NLS-1$ + public static final String DIAGRAMMING_CONTEXT = "org.simantics.modeling.ui.diagramming"; //$NON-NLS-1$ private static final String PREFERENCE_VIRTUAL_GRAPH = "preferences"; //$NON-NLS-1$ private static final boolean PROFILE = false; @@ -233,6 +236,7 @@ public class DiagramViewer protected GridSnapAdvisor snapAdvisor; private RuntimeDiagramManager runtimeDiagramManager; + private HasDiagramSourceListener hasDiagramSourceListener; /** * Set externally in @@ -631,14 +635,35 @@ public class DiagramViewer * @throws DatabaseException */ protected IDiagram loadDiagram(IProgressMonitor monitor, Resource diagram, IHintContext initialHints) throws DatabaseException { - RuntimeDiagramManager rtdm = runtimeDiagramManager; - Resource runtimeDiagram = rtdm != null ? rtdm.getRuntimeDiagram() : null; - IDiagramLoader loader = synchronizer; - if (rtdm == null || runtimeDiagram == null || loader == null) - return null; - IDiagram d = sessionContext.getSession().syncRequest( - DiagramRequests.loadDiagram(monitor, getResourceInput2().getModel(null), diagram, - runtimeDiagram, null, loader, initialHints)); + RuntimeDiagramManager rtdm = runtimeDiagramManager; + Resource runtimeDiagram = rtdm != null ? rtdm.getRuntimeDiagram() : null; + IDiagramLoader loader = synchronizer; + if (rtdm == null || runtimeDiagram == null || loader == null) + return null; + IDiagram d = sessionContext.getSession().syncRequest((Read) graph -> { + IDiagram result = DiagramRequests.loadDiagram(monitor, getResourceInput2().getModel(null), diagram, + runtimeDiagram, null, loader, initialHints).perform(graph); + + // #399: Enable certain PropertyTester implementation without database transactions + ModelingResources MOD = ModelingResources.getInstance(graph); + Resource composite = graph.getPossibleObject(diagram, MOD.DiagramToComposite); + result.setHint( + DiagramModelHints.KEY_DIAGRAM_RESOURCE_TYPE_URIS, + graph.syncRequest(new TypeURIs(diagram))); + result.setHint( + DiagramModelHints.KEY_MAPPED_COMPOSITE_RESOURCE_TYPE_URIS, + composite != null ? graph.syncRequest(new TypeURIs(composite)) : Collections.emptySet()); + + Resource diagramSource = graph.syncRequest( + new PossibleObject(diagram, MOD.HasDiagramSource), + hasDiagramSourceListener = new HasDiagramSourceListener(sourceDiagramContainer)); + ElementUtils.setOrRemoveHint( + result, + DiagramModelHints.KEY_HAS_DIAGRAM_SOURCE, + diagramSource); + + return result; + }); return d; } @@ -923,6 +948,12 @@ public class DiagramViewer } disposed = true; + + if (hasDiagramSourceListener != null) { + hasDiagramSourceListener.dispose(); + hasDiagramSourceListener = null; + } + if (activation != null) { activation.deactivate(); activation = null; diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/HasDiagramSourceListener.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/HasDiagramSourceListener.java new file mode 100644 index 000000000..c7873676b --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/HasDiagramSourceListener.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2019 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * Semantum Oy - initial API and implementation, gitlab #399 + *******************************************************************************/ +package org.simantics.modeling.ui.diagramEditor; + +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.DisposableListener; +import org.simantics.diagram.ui.DiagramModelHints; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.utils.DataContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.41.0, 1.35.2 + * @see gitlab #399 + */ +class HasDiagramSourceListener extends DisposableListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(HasDiagramSourceListener.class); + + private DataContainer diagramContainer; + + public HasDiagramSourceListener(DataContainer diagramContainer) { + this.diagramContainer = diagramContainer; + } + + @Override + public void execute(Resource source) { + DataContainer c = diagramContainer; + IDiagram d = c != null ? diagramContainer.get() : null; + if (d != null) { + ElementUtils.setOrRemoveHint(d, DiagramModelHints.KEY_HAS_DIAGRAM_SOURCE, source); + } + } + + @Override + public void exception(Throwable t) { + LOGGER.error("Received unexpected exception", t); + } + + @Override + public void dispose() { + super.dispose(); + diagramContainer = null; + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java index 714e72eb6..fb6b31382 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java @@ -46,8 +46,7 @@ public class SyncCurrentTypicalInstanceWithTemplate { if (DatabaseJob.inProgress()) return false; if (activeEditor.getEditorInput() instanceof IResourceEditorInput) { - IResourceEditorInput input = (IResourceEditorInput) activeEditor.getEditorInput(); - return TypicalPropertyTester.isTypicalInstanceEditor(Simantics.getSession(), input.getResource()); + return TypicalPropertyTester.isTypicalInstanceEditor(activeEditor); } else { return false; } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java index bbafb03e0..9fc604c6f 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java @@ -45,8 +45,7 @@ public class SyncCurrentTypicalTemplateToInstances { if (DatabaseJob.inProgress()) return false; if (activeEditor.getEditorInput() instanceof IResourceEditorInput) { - IResourceEditorInput input = (IResourceEditorInput) activeEditor.getEditorInput(); - return TypicalPropertyTester.isTypicalMasterEditor(Simantics.getSession(), input.getResource()); + return TypicalPropertyTester.isTypicalMasterEditor(activeEditor); } else { return false; } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/property/TypicalPropertyTester.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/property/TypicalPropertyTester.java index 679647a72..b222d23e4 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/property/TypicalPropertyTester.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/property/TypicalPropertyTester.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,26 +8,31 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - gitlab #399 *******************************************************************************/ package org.simantics.modeling.ui.property; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; + import org.eclipse.core.expressions.PropertyTester; -import org.eclipse.ui.IEditorInput; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.ui.IEditorPart; -import org.simantics.DatabaseJob; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; -import org.simantics.db.Session; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.utils.RequestUtil; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.diagram.ui.DiagramModelHints; +import org.simantics.g2d.diagram.IDiagram; import org.simantics.modeling.ModelingResources; +import org.simantics.modeling.ui.diagramEditor.DiagramViewer; import org.simantics.ui.SimanticsUI; -import org.simantics.ui.workbench.IResourceEditorInput; -import org.simantics.utils.ui.ErrorLogger; /** * @author Tuukka Lehtonen @@ -49,74 +54,90 @@ public class TypicalPropertyTester extends PropertyTester { public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) { //System.out.println("TEST: " + receiver + ", " + property + ", " + Arrays.toString(args) + ", " + expectedValue); - try { - Session session = Simantics.peekSession(); - if (session == null) - return false; - - if (!(receiver instanceof IEditorPart)) - return false; - IEditorPart editor = (IEditorPart) receiver; - IEditorInput in = editor.getEditorInput(); - if (!(in instanceof IResourceEditorInput)) - return false; - IResourceEditorInput input = (IResourceEditorInput) in; - final Resource inputResource = input.getResource(); - - if (DatabaseJob.inProgress()) { - // See Apros issue #9115 - // Return true because it is often possible that the database - // will be busy when these properties are tested. In such cases - // the handlers/menu contributions using these tests would - // become disabled unless we return true here. It is up to the - // handlers to also make sure that their input is valid. - return true; - } + if (!(receiver instanceof IEditorPart)) + return false; - if (IS_TYPICAL_MASTER_EDITOR.equals(property)) { - return isTypicalMasterEditor(session, inputResource); - } else if (IS_TYPICAL_INSTANCE_EDITOR.equals(property)) { - return isTypicalInstanceEditor(session, inputResource); - } - } catch (DatabaseException | InterruptedException e) { - ErrorLogger.defaultLogError(e); + if (IS_TYPICAL_MASTER_EDITOR.equals(property)) { + return isTypicalMasterEditor((IEditorPart) receiver); + } else if (IS_TYPICAL_INSTANCE_EDITOR.equals(property)) { + return isTypicalInstanceEditor((IEditorPart) receiver); } return false; } - public static boolean isTypicalMasterEditor(RequestProcessor processor, final Resource editorInputResource) throws DatabaseException, InterruptedException { + private static IDiagram getDiagram(IAdaptable editor) { + DiagramViewer viewer = editor.getAdapter(DiagramViewer.class); + return viewer != null ? viewer.getAdapter(IDiagram.class) : null; + } + + private static Set getDiagramMappedCompositeTypes(IDiagram diagram) { + Set result = diagram != null ? diagram.getHint(DiagramModelHints.KEY_MAPPED_COMPOSITE_RESOURCE_TYPE_URIS) : null; + return result != null ? result : Collections.emptySet(); + } + + private static Set getDiagramMappedCompositeTypes(IAdaptable editor) { + return getDiagramMappedCompositeTypes( getDiagram(editor) ); + } + + public static boolean isTypicalMasterEditor(IAdaptable editor) { + Set types = getDiagramMappedCompositeTypes(editor); + return types.contains(ModelingResources.URIs.MasterTypicalCompositeType); + } + + private static boolean hasDiagramSource(IDiagram diagram) { + return diagram.getHint(DiagramModelHints.KEY_HAS_DIAGRAM_SOURCE) != null; + } + + public static boolean isTypicalInstanceEditor(IAdaptable editor) { + IDiagram diagram = getDiagram(editor); + if (diagram == null) + return false; + Set types = getDiagramMappedCompositeTypes(diagram); + return !types.contains(ModelingResources.URIs.MasterTypicalCompositeType) + && types.contains(ModelingResources.URIs.TypicalComposite) + && hasDiagramSource(diagram); + } + + private static boolean timeoutingRead(RequestProcessor processor, Read read) throws DatabaseException, InterruptedException { return RequestUtil.trySyncRequest( Simantics.getSession(), SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT, SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT, false, - new UniqueRead() { + read); + } + + public static boolean isTypicalMasterEditor(RequestProcessor processor, Resource editorInputResource) throws DatabaseException, InterruptedException { + return timeoutingRead(processor, new UniqueRead() { @Override public Boolean perform(ReadGraph graph) throws DatabaseException { - ModelingResources MOD = ModelingResources.getInstance(graph); - Resource composite = graph.getPossibleObject(editorInputResource, MOD.DiagramToComposite); - return composite != null - && graph.isInstanceOf(composite, MOD.MasterTypicalCompositeType); + return isTypicalMasterEditor(graph, editorInputResource); } }); } - public static boolean isTypicalInstanceEditor(RequestProcessor processor, final Resource editorInputResource) throws DatabaseException, InterruptedException { - return RequestUtil.trySyncRequest( - Simantics.getSession(), - SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT, - SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT, - false, - new UniqueRead() { + public static boolean isTypicalInstanceEditor(RequestProcessor processor, Resource editorInputResource) throws DatabaseException, InterruptedException { + return timeoutingRead(processor, new UniqueRead() { @Override public Boolean perform(ReadGraph graph) throws DatabaseException { - DiagramResource DIA = DiagramResource.getInstance(graph); - ModelingResources MOD = ModelingResources.getInstance(graph); - return graph.isInstanceOf(editorInputResource, DIA.Diagram) - && graph.hasStatement(editorInputResource, MOD.HasDiagramSource); + return isTypicalInstanceEditor(graph, editorInputResource); } }); } + public static boolean isTypicalMasterEditor(ReadGraph graph, Resource editorInputResource) throws DatabaseException { + ModelingResources MOD = ModelingResources.getInstance(graph); + Resource composite = graph.getPossibleObject(editorInputResource, MOD.DiagramToComposite); + return composite != null + && graph.isInstanceOf(composite, MOD.MasterTypicalCompositeType); + } + + public static boolean isTypicalInstanceEditor(ReadGraph graph, Resource editorInputResource) throws DatabaseException { + DiagramResource DIA = DiagramResource.getInstance(graph); + ModelingResources MOD = ModelingResources.getInstance(graph); + return graph.isInstanceOf(editorInputResource, DIA.Diagram) + && graph.hasStatement(editorInputResource, MOD.HasDiagramSource); + } + }