Code Monkey home page Code Monkey logo

emfcloud-modelserver's People

Contributors

camilleletavernier avatar cbos avatar cdamus avatar dependabot[bot] avatar eneufeld avatar martin-fleck-at avatar ndoschek avatar planger avatar sgraband avatar tortmayr avatar vhemery avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emfcloud-modelserver's Issues

Requesting and subscribing to submodels

I think we should add the possibility to request and subscribe to changes of "submodels", ie elements and their contained elements. For listening to changes of submodels, we may want to take a look at util code of EMF ECP, I believe there are ready-to-use classes/adapters that make it easy to listen to changes in submodels efficiently.

Request server/configure does not return JsonResponse anymore

The DefaultServerController should send a success JsonResponse if workspace initialization is completed.
Returning no response at all will cause the following error:

ERROR Request configure failed with error: invalid json response body at http://localhost:8081/api/v1/server/configure reason: Unexpected end of JSON input FetchError: invalid json response body at http://localhost:8081/api/v1/server/configure reason: Unexpected end of JSON input

Model edition may load and edit another resource instead of the managed one.

When loading a resource, the method org.eclipse.emfcloud.modelserver.emf.common.ModelResourceManager.adaptModelUri(String) gets called for fixing the URI.
As a result, the URI is normalized, replacing (for example) file:///d:/myModel.coffee with file:/d:/myModel.coffee.

On the other hand, when creating a command, the owner's ModelServerReferenceDescription (when using uri.toString() without the skipEncoding attribute) may look like file:///d%3A/myModel.cofee#... which, after json decoding and EMF resolution, gives a model element from resource with URI file:///d%3A/myModel.cofee.

The direct consequence is that the new resource is loaded and edited (in the same resource set) while the previously loaded resource is not edited. When loading element back, I hence get the original element from the non-edited resource.
Note that there may also be OS-specific factors here...

I've identified 3 ways of fixing it :

  • the easiest (and dirtiest) : on the front side, by using a ModelServerReferenceDescription with the normalized URI (knowing the server implementation).
  • using a fixed URIHandler (which calls adaptModelUri) during json parsing (IMHO the best option, but not the easiest). This uri handler must be set on org.emfjson.jackson.module.EMFModule before setting up the mapper, and in this case, we must no longer call org.emfjson.jackson.module.EMFModule.setupDefaultMapper(JsonFactory) (directly or indirectly), which use a new EMFModule. (note by the way that we do not always use the ObjectMapper bound by ModelServerModule in controllers implementations, and this looks intended...)
  • by setting a URIConverter on the resource set which will adapt the model URI before loading the resource. (the difficulty is not to have conflicts with a user-custom URIConverter on the resource set)

For now, I've successfully used the 1st fix as a workaround to edit my models.

Notify any subscribers during workspace change

During re-initialization of the model repository, we need to notify subscribers that the existing resources were deleted. So, for each resource in the resource set, if it was loaded, send a delete notification (resources that weren't loaded by the client didn't exist anyways as far as the client is concerned).

Improve documentation of example implementations

  • Enhance ExampleModelServerSubscriptionClient and document properly, such that this client can be used as a kind of beginner's tutorial
  • Consider moving example implementations in README to separate wiki pages

Improve Log Configuration

We need to improve our Logging configuration at some point. Currently, the Logger just forwards to System.Out. Ideally, errors should be printed to System.error so I can react in the Theia Backend by listening to the error stream. However, for now, we bypassed this problem by setting the log level to error via CLI argument.

Reconsider 'DefaultModelRepository' and 'ModelResourceManager'

Originally we started with the DefaultModelRepository to manage a repository of all models and provide CRUD API. However, with the customization of resource sets and editing domains, we introduced the ModelResourceManager. Over time the API of those two classes have very much aligned. I therefore open the discussion whether we still need both classes. I suggest to either merge the two or find a more meaningful distinction between them.

Add session handling

Each session needs its own ResourceSet/EditingContext in order to properly support commands.

However, we first need to define whether we make it a rule that one modelserver only serves one user (always and forever ;)) and specify the use cases that we'd like to cover. If our usecases don't require a session, we can close this issue without an implementation, but I think it is worth discussing and defining it in the course of this issue, which is why we set it to high priority.

Adding a pattern validation causes exception

Adding a pattern validation causes the following exception when running the "validation" endpoint:

java.lang.IllegalArgumentException: No serializer found for class org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil$PatternMatcherImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.eclipse.emf.common.util.BasicEList$UnmodifiableEList[2]->org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil$PatternMatcherImpl[0])
at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:2978)
at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelValidator.validate(DefaultModelValidator.java:63)
at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelController.validate(DefaultModelController.java:213)
at org.eclipse.emfcloud.modelserver.emf.common.ModelServerRoutingV1.lambda$23(ModelServerRoutingV1.java:138)
at java.base/java.util.Optional.ifPresentOrElse(Optional.java:201)
at org.eclipse.emfcloud.modelserver.emf.common.ModelServerRoutingV1.validateModel(ModelServerRoutingV1.java:137)
at io.javalin.core.security.SecurityUtil.noopAccessManager(SecurityUtil.kt:23)
at io.javalin.http.JavalinServlet$addHandler$protectedHandler$1.handle(JavalinServlet.kt:121)
at io.javalin.http.JavalinServlet$service$2$1.invoke(JavalinServlet.kt:45)
at io.javalin.http.JavalinServlet$service$2$1.invoke(JavalinServlet.kt:24)
at io.javalin.http.JavalinServlet$service$1.invoke(JavalinServlet.kt:129)
at io.javalin.http.JavalinServlet$service$2.invoke(JavalinServlet.kt:40)
at io.javalin.http.JavalinServlet.service(JavalinServlet.kt:81)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.javalin.websocket.JavalinWsServlet.service(JavalinWsServlet.kt:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:791)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:550)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at io.javalin.core.JavalinServer$start$wsAndHttpHandler$1.doHandle(JavalinServer.kt:49)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1350)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:179)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:135)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil$PatternMatcherImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.eclipse.emf.common.util.BasicEList$UnmodifiableEList[2]->org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil$PatternMatcherImpl[0])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:404)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serializeContents(ObjectArraySerializer.java:252)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:213)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:22)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2804)
at com.fasterxml.jackson.databind.util.TokenBuffer.writeObject(TokenBuffer.java:936)
at com.fasterxml.jackson.core.JsonGenerator.writeObjectField(JsonGenerator.java:1769)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:78)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:1)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2804)
at com.fasterxml.jackson.databind.util.TokenBuffer.writeObject(TokenBuffer.java:936)
at com.fasterxml.jackson.core.JsonGenerator.writeObjectField(JsonGenerator.java:1769)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:79)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:1)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2804)
at com.fasterxml.jackson.databind.util.TokenBuffer.writeObject(TokenBuffer.java:936)
at com.fasterxml.jackson.core.JsonGenerator.writeObjectField(JsonGenerator.java:1769)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:79)
at org.eclipse.emfcloud.modelserver.emf.common.ValidationMapperModule$BasicDiagnosticSerializer.serialize(ValidationMapperModule.java:1)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2804)
at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:2973)
... 44 more

The following changes were done to the Coffee model:

  <eClassifiers xsi:type="ecore:EClass" name="Machine" eSuperTypes="#//Component">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="#//String3Chars"/>

  <eClassifiers xsi:type="ecore:EDataType" name="String3Chars" instanceClassName="java.lang.String">
    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
      <details key="maxLength" value="3"/>
      <details key="pattern" value="[A-Z0-9_]+"/>
    </eAnnotations>
  </eClassifiers>

And the following model resource was created:

{
"eClass" : "http://www.eclipsesource.com/modelserver/example/coffeemodel#//Machine",
"name" : "hello"
}

Without the pattern validation, the "validation" endpoint successfully completed, and reported that the name "hello" was too long. However, with the pattern validation, the above exception was raised.

Typeschema does not return all information

We can request a typeschema via a request to this url: api/v1/typeschema?modeluri=...

But the returned schema, only returns information about the direct class, but not information of the super class.
We have a test model where we have a common ecore model with interfaces, and we have 2 derived ecore models. The specific field attributes or relations defined in the derived model are returned, but the attibutes and relations in the common model are not returned even no references.
Due to that the returned typeschema is incomplete.

Either it should return a reference to these schemas or it should include it.

Snapshot failure

com.eclipsesource.workflow.glsp.server 0.0.1-SNAPSHOT FAILURE
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project com.eclipsesource.workflow.glsp.server: Compilation failure: Compilation failure:
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerAccess.java:[34,35] package org.eclipse.emf.edit.domain does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerAccess.java:[35,35] package org.eclipse.emf.edit.domain does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerAccess.java:[66,17] cannot find symbol
[ERROR] symbol: class EditingDomain
[ERROR] location: class com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerAccess
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerAccess.java:[195,16] cannot find symbol
[ERROR] symbol: class EditingDomain
[ERROR] location: class com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerAccess
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/AbstractCreateNodeHandler.java:[19,36] package org.eclipse.emf.edit.command does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/AbstractCreateEdgeHandler.java:[17,36] package org.eclipse.emf.edit.command does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/ApplyLabelEditOperationHandler.java:[17,36] package org.eclipse.emf.edit.command does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerSubscriptionListener.java:[25,35] package org.eclipse.emf.edit.domain does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerSubscriptionListener.java:[116,48] cannot find symbol
[ERROR] symbol: class EditingDomain
[ERROR] location: class com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerSubscriptionListener
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/WorkflowGLSPModule.java:[14,37] package org.eclipse.emf.edit.provider does not exist
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerAccess.java:[75,42] cannot find symbol
[ERROR] symbol: class AdapterFactoryEditingDomain
[ERROR] location: class com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerAccess
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/AbstractCreateNodeHandler.java:[51,38] cannot find symbol
[ERROR] symbol: variable AddCommand
[ERROR] location: class com.eclipsesource.workflow.glsp.server.handler.operation.AbstractCreateNodeHandler
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/AbstractCreateEdgeHandler.java:[50,38] cannot find symbol
[ERROR] symbol: variable AddCommand
[ERROR] location: class com.eclipsesource.workflow.glsp.server.handler.operation.AbstractCreateEdgeHandler
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/handler/operation/ApplyLabelEditOperationHandler.java:[45,38] cannot find symbol
[ERROR] symbol: variable SetCommand
[ERROR] location: class com.eclipsesource.workflow.glsp.server.handler.operation.ApplyLabelEditOperationHandler
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/model/WorkflowModelServerSubscriptionListener.java:[65,25] cannot find symbol
[ERROR] symbol: class EditingDomain
[ERROR] location: class com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerSubscriptionListener
[ERROR] /Users/Experiment/Desktop/TestCoffee/coffee-editor/backend/plugins/com.eclipsesource.workflow.glsp.server/src/main/java/com/eclipsesource/workflow/glsp/server/WorkflowGLSPModule.java:[125,59] cannot find symbol
[ERROR] symbol: class ComposedAdapterFactory
[ERROR] location: class com.eclipsesource.workflow.glsp.server.WorkflowGLSPModule
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Extend UnitTests

  • SessionControllerTest (e.g. if modelChanged is called upon change/deletion)
  • add missing tests (e.g. ModelController, ModelRepository...)

Mocking WsContext.pathParam sometimes results in WrongTypeOfReturnValue exception

Since updating to the latest version of Kotlin in #56 the JUnit tests seem to fail sometimes with the following error:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
String cannot be returned by pathParam()
pathParam() should return Validator
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
   Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - 
   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

	at org.eclipse.emfcloud.modelserver.emf.common.SessionControllerTest.initializeWsMessageContext(SessionControllerTest.java:190)
	at org.eclipse.emfcloud.modelserver.emf.common.SessionControllerTest.testSubscribeAndSendKeepAlive(SessionControllerTest.java:159)

After investigating that for a bit, it seems that there was a change that marked the method pathParam with @JvmSynthetic to might have fixed that but did not in our case: javalin/javalin@be8910b.

There are already some open issues related to this:

The problem should be investigated and fixed, either by re-writing the mocking code, downgrading to a Javalin version that works (previously we used 3.1.0) of finding another way to get the test cases to run properly.

Reconsider incremental update for model server

Currently our incremental update consists of a serialized (JSON, XMI) version of the executed command on the command stack. Interpreting these commands may result in problems for generic views.

Therefore I would like to open the discussion on whether it might be more useful to simply send a list of changed model element URIs as update. Clients could then decide to generically re-query those model elements and update their representation.

To not lose any functionality, I think we can keep the subscription to the commands but maybe rename it to a subscription to the command stack instead of the models.

Make model loading/creation of editing domain configurable

Currently the model server creates the editing domain, the resource set and loads the model all by itself. However, there might be cases where additional resources should be loaded in the corresponding resource set/editing domain. We therefore should provide an Interface and default implementation for the model loading that is bound in the model server module so that it can be customized. By default each resource should be loaded in a separate editing domain, see implementation provided in issue #50.

Ability to close resource without saving

The Model Server API does not offer the capability to simply stop editing a resource without saving.
If we plug an editor to it, when we close the editor, the resource is still opened and dirty by the model server. Hence, when the user reopens it, expecting the original resource, he gets the dirty unsaved resource instead.

For such purpose, a close resource method would be very handy, which would reset the command stack in DefaultModelRepository (which keeps all models loaded), or even close the resource and resource set in a lazier implementation.
For the DefaultModelRepository implementation, where all models are loaded, a workaround would would be to undo all modifications. But it would be better to have another atomic dedicated method working with other implementations.

The ModelRepository / ModelResourceManager interfaces have the removeResource / removeModel method, but this one is a bit too final for this purpose and deletes the model file.
Please let me know if there already is a dedicated method I've missed...

Complete the API with an eContainer method

I just noticed that the model server does not expose a method to get the eContainer of a loaded EObject.
This is quite necessary, because metamodels rarely specialize the eContainer relationship. So when we get a model element with the model server API, we loose the ability to get the eContainer like with native EMF.
Obviously, loading the whole model to find the container is not an option. For such a special relationship, a new GET method semms quite a reasonable solution.

PS : please tag as [enhancement]

Stabilize broadcasting of incremental command updates

In case of editing the name of an element (which also changes its SemanticUriFragment) via a SetCommand, the broadcasted incrementalUpdate (command) does not contain the correct element values in all cases.

Example:
EClass with name "BrewingUnit" -> set name "BrewingUnitNew"
-> SemanticUriFragment changes from "//BrewingUnit" to "//BrewingUnitNew"

If the command is encoded after executing the SetCommand, the broadcasted incrementalUpdate contains the updated element "//BrewingUnitNew" as owner and therefore the listeners have troubles consuming that update correctly.

As we already pre-encode commands in the case of Undo/Redo (to ensure proper command values for broadcasting to all listeners) we should stick to this behaviour also for executing other commands.

Improve extensibility of model server formats and codecs

As reported on Spectrum, the model server does not provide any way to add custom codecs or replace existing ones. The main reason for this is that we have a single Codecs class that has the two by-default supported formats (XMI, JSON) hard-coded.

The goal of this task it to improve on that situation by allowing the user to register/bind new codecs or replace existing ones.

As a suggestion: Make the codecs configurable with DI:

  • Support binding codecs using their interface in the the ModelServerModule. For this the interface could be enhanced with the extension/format the codec handles and a priority if necessary. It should be easily possible to register multiple codecs. The DefaultModelServerModule should at least bind the two default codecs.
  • Add a binding for a manager (CompoundCodec, CodecManager or something similar) that reads out the list of bound codecs and offers query methods similar to what the Codecs class offers now. The manager is then injected where necessary but might also be overwritten/rebound in a custom module.

Improve ModelServerLauncher for easier customization

Currently the model server launcher provides some methods to add customizations, e.g., addEPackageConfigurations. However, in other cases no such method exists, e.g., when trying to add additional routing, see [1] and [2]. I believe the API could be improved in this regard to allow easier integration of additional modules (generics in the return type of getModules make it unnecessarily difficult) and to already provide hooks for classes which may be implemented more than once, i.e., that have a collection binding.

I believe we could discuss whether that improved customizations should be part of the ModelServerModule itself or the ModelServerLauncher.

[1] https://spectrum.chat/emfcloud/modelserver/model-server-api-to-return-models-of-a-specific-type~b4a27e5d-48e6-41fe-8177-f66056f8c77f
[2] 954ffed

Model server reports illegal reflective access error on start up of coffee editor

Directly after launching the coffee editor, the following editor is reported on the console.

root INFO Theia app listening on http://localhost:3000.
root ERROR ModelServerBackendContribution: WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$2 (file:/home/lucas/Git/coffee-editor/web/coffee-server/build/workflow-modelserver-example-1.2.0-SNAPSHOT-glsp.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$2
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Process incoming requests after server configuration is completed

During server configuration is running, resources inside the given workspaceRoot are loaded. If an incoming request fetches a model, this might lead to an error, as the initializtion might not be completed yet.
Therefore incoming requests should be processed as soon as the server configuration for initializing the model server is complete.

Request server/configure does not deliver JsonResponse

Since #73 the PUT request server/configure does not deliver the expected JsonResponse (success or error) anymore.

Clients expect a boolean response though. Here is an example of the typescript client reacting to the missing response:

ERROR Request configure failed with error:
invalid json response body at http://localhost:8081/api/v1/server/configure
reason: Unexpected end of JSON input

Support Undo/Redo API

  • undo and redo commands on the edit endpoint
  • on undo, compute the inverse of the command that was undone and send that to subscribers for incremental update notification
  • on redo, send the redone command to subscribers
  • ensure that the save API tells the CommandStack that save was done
  • if undo returns to the last savepoint, notify subscribers about dirty state change (command-stack listener)

[Model Server] Create bi-directional references

Bi directional references are a bit specific, as they require creating multiple related elements. Atomically, we need to:

  • Create the first reference (A)
  • Create the second reference (B)
  • Set A as the opposite of B

The problem is that until A and B are actually created on the Model Server side, it is not possible to properly define the Set command.

Add support for custom command

At the moment the list of supported commands is fixed in the Command.ecore metamodel. If a client sends a command matching one of the classes, it will be decoded into an EMF command, executed on the command stack and finally sent as Json or XMI to the clients as incremental update.

For some languages, however, it might be useful to integrate their own commands. At the moment this is only possible by extending the metamodel and providing a custom CommandCodec that translates the CCommand to an EMF command. The goal of this task is therefore to provide a generic "custom command" in our Command.ecore that holds a map of key-value pairs that can be interpreted by the specific languages. Additionally, a use case for such a command should be added to our example.

GetAll request is failing

Requesting all available models from the model server via "GetAll" (http://localhost:8081/api/v1/models) fails with an internal server error:

WARN io.javalin.Javalin  - Uncaught exception
org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=0, size=0 ...

Model Server initialization loads all models

The default implementation of the ModelResourceManager loads all available models on startup (DefaultModelResourceManager.initialize() => DefaultModelResourceManager.loadSourceResources(String))

This may become an issue for larger repositories, as loading everything may not scale (Both in terms of CPU time and Memory usage).

Moreover, the current implementation of DefaultModelRepository.getAllModels() only returns loaded models (So it would no longer work if we introduced lazy loading). I think this method (in its current form) is not really relevant anyway, as retrieving all model instances wouldn't scale either. It would make more sense to return an index of models (URIs only), without actually loading them, and regardless of whether these models are already load or not.

This may be (vaguely) related to Issue #86 (for the relationship between ModelRepository and ModelManager)

So I suggest the following changes:

  • Change the behavior of getAllModels() to return an index of available models (loaded or not, URIs only)
  • Change the behavior of DefaultModelResourceManager.initialize() to remove the part where models are actually loaded (We may also consider removing the ResourceSet creation, but this may have a larger impact, as most other methods will rely on the ResourceSet map to determine if a model exists).
  • Merge ModelRepository and ModelManager (That's issue #86). Except for the "get..." vs "getLoaded..." APIs, both interfaces already seem properly aligned

Export missing util packages

Export missing *.util packages (e.g. org.eclipse.emfcloud.modelserver.edit.util) to be able to access their methods.

Saving an unkown resource should not respond 'success'

When trying to save an unknown resource, the model server responds with success:
{ "type": "success", "data": "Model 'file:/...' successfully saved" }

This is not correct, it should return an error, just like for example the DELETE endpoint.
{ "type": "error", "data": "Model 'file:/...' not found, cannot be deleted!" }

Unit tests failing on windows due to OS-specific constructions

When executing on windows, unit tests in org.eclipse.emfcloud.modelserver.emf.tests fail. (on master branch, commit 4d383b9 )
image
Some are due to #63 , but there are other causes, most probably specific to the windows OS.

The following tests fail due to a difference in whitespaces characters (mainly "\n" vs "\r\n" line breaks) :

  • org.eclipse.emfcloud.modelserver.emf.common.ModelControllerTest.getModelelementByNameXmiFormat()
  • org.eclipse.emfcloud.modelserver.emf.common.ModelControllerTest.getModelelementByIdXmiFormat()
  • org.eclipse.emfcloud.modelserver.emf.EMFJsonConverterTest.testToJsonSimple()
  • org.eclipse.emfcloud.modelserver.emf.EMFJsonConverterTest.testToJsonCoffeeJson()
    I suggest calling org.junit.platform.commons.util.StringUtils.replaceWhitespaceCharacters(String, String) when comparing strings to avoid this issue.

Some other tests fail with "java.lang.IllegalArgumentException: resolve against non-hierarchical or relative base". This is the case of :

  • org.eclipse.emfcloud.modelserver.emf.common.ModelControllerTest.executeCommand()
  • org.eclipse.emfcloud.modelserver.emf.common.ModelControllerTest.addCommandNotification()
    We'll have to investigate more, but my first guess would be a difference of separator in constructed URIs.

Finally, these tests fail (directly or indirectly) due to differences in built URIs (difference of separator) :

  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.normalizeWorkspaceRoot()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.getUiSchemaFolder()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.normalizeWorkspaceRootSlashAlreadyPresent()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.setWorkspaceRoot()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.normalizeWorkspaceRootEncoded()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.getWorkspaceEntries()
    And also probably (but must be confirmed by investigation) :
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.isUiSchemaFolder()
  • org.eclipse.emfcloud.modelserver.emf.configuration.ServerConfigurationTest.isValidFileURI()

Each resource should be loaded in a separate editing domain

To improve the undo/redo support each resource identified by the model URI should be loaded in a separate editing domain and a separate resource set. All edit operations are handled by the editing domain associated with the respective resource.

This behavior opens up the possibility to have two editing domains/resource sets loading the same model (either directly or through cross references). Therefore, after performing a save operation a notification should be sent out to all listeners of that file that the underlying content has changed.

Absolute full path as modelURI causes error

Using an absolute full path like file:///home/destination/file.coffee leads to the following error:

9765 [qtp1598898814-26] DEBUG DefaultModelResourceManager  - Could not load resource with URI: file:///home/nina/Clients/OpenSource/emfcloud/emfcloud-modelserver/examples/org.eclipse.emfcloud.modelserver.example/.temp/workspace/SuperBrewer3000.coffee
[qtp1598898814-26] WARN io.javalin.Javalin - Uncaught exception
java.lang.NullPointerException
	at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelResourceManager.removeResource(DefaultModelResourceManager.java:194)
	at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelResourceManager.removeResourceSafe(DefaultModelResourceManager.java:186)
	at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelResourceManager.loadResource(DefaultModelResourceManager.java:178)
	at org.eclipse.emfcloud.modelserver.emf.common.DefaultModelResourceManager.loadResource(DefaultModelResourceManager.java:165)
	at org.eclipse.emfcloud.modelserver.emf.common.ModelRepository.getModel(ModelRepository.java:59)
	at org.eclipse.emfcloud.modelserver.emf.common.ModelController.getOne(ModelController.java:106)
...

Move example project to dedicated coffee model example repository

The example project is only used in test cases and the example and should be removed from the overall repository in the long term. If the project is removed at least the following changes need to be made:

  • Remove dependencies from other projects, especially the test projects and the example project
  • Remove CoffeePackageConfiguration and example resources from example project and add other resources so that we have at least one more model in the repository when starting the example.
  • Update README to reflect the removal of the SuperBrewer3000.json file.

Reconsider log levels of some calls

Currently, there are two places where we log errors directly to the console even though the test does not fail:

  • EMFJsonConverterTest calls EMFJsonConverter#fromJson which logs the error even though that is expected in some test cases.
  • ModelRepositoryTest calls ResourceManager#loadResource logs all resources it cannot load to the console but the ModelRepository#initialize simply iterates over all files, so many files will not be loaded as resources, e.g., Java files, preference files, etc. We should at least consider changing the level to warning as requesting non-existing resources is not so uncommon.

cf. also #6 about general logging configuration.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.