From 13f24e83f3b2b2b232fbefe6dabb676b7a973c95 Mon Sep 17 00:00:00 2001 From: Andreas Bayha <bayha@fortiss.org> Date: Thu, 27 Apr 2023 14:32:05 +0200 Subject: [PATCH] ConstraintCheckerService: Added support for asynchronous checks Extended the IConstraintCheckerService and MarkerService to allow registration and execution of asynchronous constraint checkers which do not block the constraint checker service. Issue-ref: 4309 Issue-URL: af3#4309 Signed-off-by: Andreas Bayha <bayha@fortiss.org> --- .../tooling/kernel/ui/internal/.ratings | 2 +- .../kernel/ui/internal/MarkerService.java | 16 ++++ .../fortiss/tooling/kernel/internal/.ratings | 2 +- .../internal/ConstraintCheckerService.java | 76 +++++++++++++++++++ .../fortiss/tooling/kernel/service/.ratings | 2 +- .../service/IConstraintCheckerService.java | 30 ++++++++ 6 files changed, 125 insertions(+), 3 deletions(-) diff --git a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/.ratings b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/.ratings index d9c3d0574..c9bdb8362 100644 --- a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/.ratings +++ b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/.ratings @@ -1,6 +1,6 @@ ActionService.java e29126b5947c9fd2f1d82bb87001b9d0ead50c3b GREEN ContextMenuService.java 9021e4eeb5d7be5d73d87e5947564bdf17f07b9d GREEN -MarkerService.java 0bfe2c67638db4e506ea5dc7680765f2a8d632e1 GREEN +MarkerService.java 92c9e7410a39040554473bd59d7b75a76ad47f97 YELLOW ModelEditorBindingService.java f304addb514cd2de443997e0b52cef7a3a9897bf GREEN ModelElementHandlerService.java 34adeef844bf98c69f1b9a7252f34d0a2b741b54 GREEN NavigatorService.java 1d773dde3791ddf7051616fe249558e7e307757d GREEN diff --git a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/MarkerService.java b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/MarkerService.java index 0bfe2c676..92c9e7410 100644 --- a/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/MarkerService.java +++ b/org.fortiss.tooling.kernel.ui/src/org/fortiss/tooling/kernel/ui/internal/MarkerService.java @@ -181,6 +181,16 @@ public class MarkerService implements IMarkerService, IPersistencyServiceListene IConstraintCheckerService ccs = IConstraintCheckerService.getInstance(); List<IConstraintViolation<? extends EObject>> checkResult = ccs.performAllConstraintChecksRecursively(rootModelElement); + + ccs.performAllAsynchronousConstrintChecksRecursively(rootModelElement, violations -> { + synchronized(violationCache) { + CacheEntry entry = getCacheEntry(element); + entry.addNewViolations(violations); + } + + updateUI.schedule(); + }); + synchronized(violationCache) { CacheEntry entry = getCacheEntry(element); entry.updateCacheEntries(checkResult); @@ -279,6 +289,12 @@ public class MarkerService implements IMarkerService, IPersistencyServiceListene updateCacheEntries(List<IConstraintViolation<? extends EObject>> newViolations) { clearCachedLists(); // update cache entries + addNewViolations(newViolations); + } + + /** Add the given violations to the cache entry. */ + public synchronized void + addNewViolations(List<IConstraintViolation<? extends EObject>> newViolations) { for(IConstraintViolation<? extends EObject> violation : newViolations) { getCachedList(violation.getSource()).add(violation); } diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings index 5d2058ca4..bed54e7c3 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings @@ -1,7 +1,7 @@ CommandLineInterfaceService.java 6b5c94c52702f773c60b181eff52204ab379b248 GREEN CommandStackService.java 957bda69b5feb91f002aed4d25ed334e92801e7e GREEN ConnectionCompositorService.java 5a52f8a3e88c167ae6909c3d9eb3fb4706177e8b GREEN -ConstraintCheckerService.java abd4667ceef11c47235e20a6566d8943f3417cf3 GREEN +ConstraintCheckerService.java 7aeea15cffbe42b5819dd77f6a386aea18def37d YELLOW DummyTopLevelElement.java 21807bbdafec2e0ef28f0ee9090218f90bd73aee GREEN ElementCompositorService.java b1924b5b349118a70149cfac5b48544897d26e9e GREEN LoggingService.java da784259f7b456b54bf75c41ec268f64919ce78d GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/ConstraintCheckerService.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/ConstraintCheckerService.java index abd4667ce..7aeea15cf 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/ConstraintCheckerService.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/ConstraintCheckerService.java @@ -17,12 +17,16 @@ package org.fortiss.tooling.kernel.internal; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableMap; +import static org.conqat.lib.commons.reflect.ReflectionUtils.performNearestClassLookup; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.function.Consumer; import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.kernel.extension.IConstraintChecker; @@ -45,6 +49,14 @@ public class ConstraintCheckerService extends EObjectAwareServiceBase<IConstrain /** The singleton instance. */ private static final ConstraintCheckerService INSTANCE = new ConstraintCheckerService(); + /** Map of all classes to the respective registered asynchronous constraint checkers. */ + Map<Class<?>, List<IConstraintChecker<EObject>>> asynchronousConstraintCheckers = + new HashMap<Class<?>, List<IConstraintChecker<EObject>>>(); + + /** Maps all constraint checkers to the last started Thread, each. */ + Map<IConstraintChecker<? extends EObject>, Thread> asynchronousChecks = + new HashMap<IConstraintChecker<? extends EObject>, Thread>(); + /** Returns singleton instance of the service. */ public static ConstraintCheckerService getInstance() { return INSTANCE; @@ -130,6 +142,50 @@ public class ConstraintCheckerService extends EObjectAwareServiceBase<IConstrain } } + /** {@inheritDoc} */ + @Override + public void performAllAsynchronousConstrintChecksRecursively(EObject modelElement, + Consumer<List<IConstraintViolation<? extends EObject>>> addMarkers) { + performAllAsynchronousConstrintChecks(modelElement, addMarkers); + + for(Iterator<EObject> iter = modelElement.eAllContents(); iter.hasNext();) { + performAllAsynchronousConstrintChecks(iter.next(), addMarkers); + } + } + + /** {@inheritDoc} */ + @Override + public void performAllAsynchronousConstrintChecks(EObject modelElement, + Consumer<List<IConstraintViolation<? extends EObject>>> addMarkers) { + List<IConstraintChecker<EObject>> asyncHandlers = + performNearestClassLookup(modelElement.getClass(), asynchronousConstraintCheckers); + + if(asyncHandlers == null) { + return; + } + + for(IConstraintChecker<EObject> checker : asyncHandlers) { + Thread checkerThread = asynchronousChecks.get(checker); + if(checkerThread != null && checkerThread.isAlive()) { + checkerThread.interrupt(); + } + + checkerThread = new Thread(new Runnable() { + @Override + public void run() { + List<IConstraintViolation<? extends EObject>> results = + new ArrayList<IConstraintViolation<? extends EObject>>(); + results.addAll(checker.apply(modelElement)); + + addMarkers.accept(results); + } + }); + asynchronousChecks.put(checker, checkerThread); + + checkerThread.start(); + } + } + /** {@inheritDoc} */ @Override public List<IConstraintChecker<? extends EObject>> @@ -179,4 +235,24 @@ public class ConstraintCheckerService extends EObjectAwareServiceBase<IConstrain public IIntrospectionDetailsItem getDetailsItem() { return new ConstraintCheckerKISSDetailsItem(unmodifiableMap(handlerMap)); } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public <T extends EObject> void registerAsynchronousConstraintChecker( + IConstraintChecker<T> checker, Class<T> modelElementClass) { + if(checker == null) { + return; + } + + List<IConstraintChecker<EObject>> checkers = + asynchronousConstraintCheckers.get(modelElementClass); + + if(checkers == null) { + checkers = new ArrayList<IConstraintChecker<EObject>>(); + asynchronousConstraintCheckers.put(modelElementClass, checkers); + } + + checkers.add((IConstraintChecker<EObject>)checker); + } } diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings index 7b59a6c18..32deb7d47 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings @@ -1,7 +1,7 @@ ICommandLineInterfaceService.java c3e3ba08b2a1b8125b43abd1c29b7dc0a0be2b80 GREEN ICommandStackService.java 678dcd1a6ab435ed0870fa2a9ec48ce47f25a187 GREEN IConnectionCompositorService.java 0cdf4568b2cd3e95ea195df90a84699eff36442b GREEN -IConstraintCheckerService.java 291e53297aaea213e07e78f63350938ee2c7b155 GREEN +IConstraintCheckerService.java ef0f6fe43e3858b145ea10da6566fd0e3b00a48f YELLOW IEclipseResourceStorageService.java b1155ca15cd9474d4d533d6cb2725e8a22040ec9 GREEN IElementCompositorService.java acd462ec15f3bcc247b544b46ceebee971fe1408 GREEN IKernelIntrospectionSystemService.java 7005c3acb4c6f978729d93279c595765e94e38eb GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/IConstraintCheckerService.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/IConstraintCheckerService.java index 291e53297..ef0f6fe43 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/IConstraintCheckerService.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/IConstraintCheckerService.java @@ -16,6 +16,7 @@ package org.fortiss.tooling.kernel.service; import java.util.List; +import java.util.function.Consumer; import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.kernel.extension.IConstraintChecker; @@ -47,6 +48,31 @@ public interface IConstraintCheckerService { List<IConstraintViolation<? extends EObject>> performAllConstraintChecksRecursively(EObject modelElement); + /** + * Performs all registered asynchronous constraint checks for the given modelElement and all its + * contained child elements. + * + * @param modelElement + * The {@link EObject} for which all checks shall be performed recursively. + * @param addMarkers + * A {@link Consumer} to receive all constraint violations from the asynchronous + * checks. + */ + void performAllAsynchronousConstrintChecksRecursively(EObject modelElement, + Consumer<List<IConstraintViolation<? extends EObject>>> addMarkers); + + /** + * Performs all registered asynchronous constraint checks for the given modelElement. + * + * @param modelElement + * The {@link EObject} for which all checks shall be performed. + * @param addMarkers + * A {@link Consumer} to receive all constraint violations from the asynchronous + * checks. + */ + void performAllAsynchronousConstrintChecks(EObject modelElement, + Consumer<List<IConstraintViolation<? extends EObject>>> addMarkers); + /** * Performs all constraint checks only on the given model element and * returns the check results. @@ -63,4 +89,8 @@ public interface IConstraintCheckerService { /** Registers the given checker with the service. */ void registerConstraintChecker(IConstraintChecker<EObject> checker, Class<?> modelElementClass); + + /** Registers the given checker to be run asynchronously in the service. */ + <T extends EObject> void registerAsynchronousConstraintChecker(IConstraintChecker<T> checker, + Class<T> modelElementClass); } -- GitLab