diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler new file mode 100644 index 000000000..6e03b9500 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler @@ -0,0 +1,3 @@ +de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler +de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler +de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeActionHandler \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend index 0c3d93bb4..738cadec9 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend @@ -16,8 +16,8 @@ */ package de.cau.cs.kieler.klighd.lsp -import java.util.HashMap -import org.eclipse.xtend.lib.annotations.Accessors +import java.util.Map +import org.eclipse.sprotty.Action /** * Abstract class to handle Sprotty actions. @@ -26,11 +26,17 @@ import org.eclipse.xtend.lib.annotations.Accessors */ abstract class AbstractActionHandler implements IActionHandler { - @Accessors(PUBLIC_GETTER, PROTECTED_SETTER) - HashMap> supportedMessages = newHashMap + Map> supportedMessages + + override Map> getSupportedMessages() { + return supportedMessages + } + + def setSupportedMessages(Map> messages) { + this.supportedMessages = messages + } override canHandleAction(String kind) { - return supportedMessages.containsKey(kind) - - } + return supportedMessages.containsKey(kind) + } } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend index 56aa23794..da17fabc2 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend @@ -17,6 +17,7 @@ package de.cau.cs.kieler.klighd.lsp import org.eclipse.sprotty.Action +import java.util.Map /** * Service Interface for ActionHandler. @@ -24,6 +25,10 @@ import org.eclipse.sprotty.Action * @author sdo */ interface IActionHandler { + + + def Map> getSupportedMessages(); + /** * Checks and returns true if this ActionHandler can handle this action. * @param kind String identifier of action diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index 26168d214..459b816a0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -20,15 +20,13 @@ import com.google.common.base.Strings import com.google.common.base.Throwables import com.google.common.io.ByteStreams import com.google.inject.Inject +import com.google.inject.Injector import de.cau.cs.kieler.klighd.IAction import de.cau.cs.kieler.klighd.IAction.ActionContext import de.cau.cs.kieler.klighd.Klighd import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.ViewContext import de.cau.cs.kieler.klighd.kgraph.KNode -import de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler -import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeActionHandler -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer import de.cau.cs.kieler.klighd.lsp.model.CheckImagesAction import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction @@ -50,8 +48,11 @@ import java.io.InputStream import java.util.ArrayList import java.util.Base64 import java.util.Collection +import java.util.HashMap import java.util.List import java.util.Map +import java.util.ServiceLoader +import java.util.Set import java.util.concurrent.CompletableFuture import org.apache.log4j.Logger import org.eclipse.core.runtime.Platform @@ -91,15 +92,9 @@ import org.eclipse.xtend.lib.annotations.Accessors class KGraphDiagramServer extends LanguageAwareDiagramServer { static val LOG = Logger.getLogger(KGraphDiagramServer) - @Inject - protected LayeredInteractiveActionHandler constraintActionHandler - - @Inject - protected MrTreeActionHandler mrTreeActionHandler + @Inject protected Injector injector - - @Inject - protected RectpackingInteractiveActionHandler rectpackingActionHandler + Map handlers = new HashMap @Inject protected KGraphDiagramState diagramState @@ -149,6 +144,13 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { currentRoot = new SModelRoot(); currentRoot.setType("NONE"); currentRoot.setId("ROOT"); + // Create map of registered action kinds and handlers. + ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + val Set kindsSupported = handler.supportedMessages.keySet + for (kind : kindsSupported) { + handlers.put(kind, handler); + } + ] } /** @@ -261,14 +263,16 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { handle(action as RefreshLayoutAction) } else if (action.getKind === RequestDiagramPieceAction.KIND) { handle(action as RequestDiagramPieceAction) - } else if (constraintActionHandler.canHandleAction(action.getKind)) { - constraintActionHandler.handle(action, clientId, this) - } else if (mrTreeActionHandler.canHandleAction(action.getKind)) { - mrTreeActionHandler.handle(action, clientId, this) - } else if (rectpackingActionHandler.canHandleAction(action.getKind)) { - rectpackingActionHandler.handle(action, clientId, this) } else { - super.accept(message) + val handlerInstance = handlers.get(action.kind) + if (handlerInstance !== null) { + // Even though we have an instance, it is not yet populated with all injected things. + val handler = injector.getInstance(handlers.get(action.kind).class) + handler.handle(action, clientId, this) + } else { + // If no handler is registered for this message. Let the default super class handle it. + super.accept(message) + } } } } catch (Exception e) { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index 3f9c852eb..c75a48d86 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -17,22 +17,10 @@ package de.cau.cs.kieler.klighd.lsp.gson_utils import com.google.gson.GsonBuilder +import com.google.inject.Injector +import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.SynthesisOption -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerPredecessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteLayerConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeletePositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteRelativeConstraintsAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteStaticConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerPredecessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetLayerConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetStaticConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeSetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingDeletePositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingSetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.SetAspectRatioAction +import de.cau.cs.kieler.klighd.lsp.IActionHandler import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction import de.cau.cs.kieler.klighd.lsp.model.PerformActionAction import de.cau.cs.kieler.klighd.lsp.model.RefreshDiagramAction @@ -40,16 +28,17 @@ import de.cau.cs.kieler.klighd.lsp.model.RefreshLayoutAction import de.cau.cs.kieler.klighd.lsp.model.RequestDiagramPieceAction import de.cau.cs.kieler.klighd.lsp.model.SetSynthesisAction import java.awt.geom.Point2D +import java.util.ServiceLoader import org.eclipse.emf.ecore.EObject import org.eclipse.sprotty.server.json.ActionTypeAdapter /** * Static util class to configure needed gson type adapters for KGraph serialization. * - * @author nre + * @author nre, sdo */ class KGraphTypeAdapterUtil { - def static GsonBuilder configureGson(GsonBuilder gsonBuilder) { + def static GsonBuilder configureGson(GsonBuilder gsonBuilder, Injector injector) { gsonBuilder .registerTypeAdapterFactory( new ActionTypeAdapter.Factory => [ @@ -60,31 +49,17 @@ class KGraphTypeAdapterUtil { addActionKind(RefreshDiagramAction.KIND, RefreshDiagramAction) addActionKind(RefreshLayoutAction.KIND, RefreshLayoutAction) - // Interactive layered actions - addActionKind(SetStaticConstraintAction.KIND, SetStaticConstraintAction) - addActionKind(SetPositionConstraintAction.KIND, SetPositionConstraintAction) - addActionKind(SetLayerConstraintAction.KIND, SetLayerConstraintAction) - addActionKind(DeleteStaticConstraintAction.KIND, DeleteStaticConstraintAction) - addActionKind(DeletePositionConstraintAction.KIND, DeletePositionConstraintAction) - addActionKind(DeleteLayerConstraintAction.KIND, DeleteLayerConstraintAction) - //relative constraints - addActionKind(SetInLayerPredecessorOfConstraintAction.KIND, SetInLayerPredecessorOfConstraintAction) - addActionKind(SetInLayerSuccessorOfConstraintAction.KIND, SetInLayerSuccessorOfConstraintAction) - addActionKind(DeleteRelativeConstraintsAction.KIND, DeleteRelativeConstraintsAction) - addActionKind(DeleteInLayerPredecessorOfConstraintAction.KIND, DeleteInLayerPredecessorOfConstraintAction) - addActionKind(DeleteInLayerSuccessorOfConstraintAction.KIND, DeleteInLayerSuccessorOfConstraintAction) - - - // Interactive rectpacking actions - addActionKind(RectpackingSetPositionConstraintAction.KIND, RectpackingSetPositionConstraintAction) - addActionKind(RectpackingDeletePositionConstraintAction.KIND, RectpackingDeletePositionConstraintAction) - addActionKind(SetAspectRatioAction.KIND, SetAspectRatioAction) + // Load all registered action handlers and add their actions. + ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + val handlerInstance = injector.getInstance(handler.class) + handlerInstance.supportedMessages.keySet.forEach[kind | + addActionKind(kind, handlerInstance.supportedMessages.get(kind)) + ] + ] // Incremental topdown actions addActionKind(RequestDiagramPieceAction.KIND, RequestDiagramPieceAction) - // Interactive mrtree actions - addActionKind(MrTreeSetPositionConstraintAction.KIND, MrTreeSetPositionConstraintAction) ] ) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend index 246644a01..efd04e19c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend @@ -124,7 +124,7 @@ abstract class AbstractLsCreator implements ILsCreator { // TypeAdapter is needed to be able to send recursive data in json val Consumer configureGson = [ gsonBuilder | - KGraphTypeAdapterUtil.configureGson(gsonBuilder) + KGraphTypeAdapterUtil.configureGson(gsonBuilder, injector) ] // Get all LSExtensions to use them as local services val localServices = newArrayList