runWriteAction

It seams to be impossible to make node changes from a non-gui thread in JetBrains MPS 2018.1.4 (Build #MPS-181.1404, built on May 23, 2018)

My (non-generated) code runs in a arbitrary (non-gui) Java thread using the mps.openapi.

1) repository.getModelAccess().runWriteAction(...) does not work (anymore) because MPS gives you the following exception:

jetbrains.mps.smodel.IllegalModelChangeError: registered node can be modified only inside a command or during model load

2) repository.getModelAccess().executeCommandInEDT(...) does not work because MPS gives you the following exception:

java.lang.UnsupportedOperationException: GlobalModelAccess does not support actions which require a command to run. One needs a project to run such actions (@see ProjectModelAccess).

In both cases this is in conflict with the documentation in the mps.openapi.

What is the meaning of a write action if you cannot make a change in it? 

Is it impossible to make node changes using GlobalModelAccess?

 

9 comments
Comment actions Permalink

I haven't encountered the problem because I'm not using 2018.1 yet but: 1) the meaning of a write action for a global repository is probably to synchronize writes to that repository, but writing to nodes in a project repository apparently requires more strict locking now. 2) how have you obtained the repository?

The documentation should be improved probably. Can you point to specific places that are now outdated?

Having one global repository used to cause problems earlier (for example, if you open two projects in MPS they get sort of "merged" together) so I'm glad that MPS is moving away from it.

1
Comment actions Permalink

Taken from the source-code of the openapi in the class org.jetbrains.mps.openapi.module.ModelAccess:

-----------

 

/**
* Modifications to models can only be performed from within managed actions, which hold the appropriate write lock.
* The method obtains such a lock and executes the provided action.
* It should not be invoked from EDT, otherwise UI freeze may occur.
* Note: A lock cannot be upgraded. When owning the read lock it is not allowed to ask for the write lock through the runWriteAction() method.
*/
void runWriteAction(Runnable r);

 

/**
* Represents a write action executed with respect to platform undo mechanism, runs asynchronously from EDT thread.
* This method may be invoked from any thread.
*/
void executeCommandInEDT(Runnable r);

-----------

I obtained the repository by using the depreciated method: MPSModuleRepository.getInstance() when initializing the application plugin.

Perhaps there is the problem. Do you know a better way?

1
Comment actions Permalink

> I obtained the repository by using the depreciated method: MPSModuleRepository.getInstance() when initializing the application plugin.

> Perhaps there is the problem. Do you know a better way?

Yes, I think this is the problem. Get the MPS project and use Project.getRepository(). If you have no project readily available, then describe what you're doing in more detail and we'll see how to get you the project :)

1
Comment actions Permalink

I am making a framework that subscribes to changes of models using SRepositoryListener, SModuleListener, SModelListener and SNodeChangeListener from the openapi. The framework is implemented in Java and makes changes in the models also using the openapi. It is initialized in a application plugin. I cannot find anything that gives me access to the project in init().

Here is the code of the  application plugin.

-----

private MyFramework framework;

init()->void {
     this.framework= new MyFramework (MPSModuleRepository.getInstance());
     this.framework.start();
}

dispose()->void {
     this.framework.stop();
}

-----

I also did not find a way to subscribe to a project (to track adding removing owned modules). That is only possible on the global repository. Nor can I find a way to determine the owning project on a module.

1
Comment actions Permalink

Can you use project plugin instead? Maybe subscribe for the module changes on the global repository but listen to the rest of the changes on projects' repositories?

1
Comment actions Permalink

Yes, it works now. Thanks!

Can i find out which modules are owned by the project?

I think it is a problem to make a change on module from a different project.

1
Comment actions Permalink

There's Project.getProjectModules()

1
Comment actions Permalink

That is simple indeed. Thanks!  

1
Comment actions Permalink

JFYI, command is required to modify nodes only when your code runs in IDE, in headless mode (e.g from some Ant tasks) write action would suffice.The difference is whether we track undo or not. I agree it's a bit tight design constraint, AFAIU the idea was to avoid hard to reproduce undo issues (when UI action modifies a model without undo context), therefore MPS enforces command on any node change. Indeed, as MPS moves forward, there'd be more scenarios when one need to modify a model without undo information recorded and limitation of a command would likely get lifted for certain scenarios. However, for project, user-visible models it's likely to persist.

As for second issue, indeed GlobalModelAccess has no idea how to perform commands, as it controls global repository, which is created way sooner than any IDE/UI. Besides, users are not expected to modify deployed modules, and have to deal with modules available from Project and its repository (in fact, there's single global repository now, but MPS moves away from this paradigm).

2

Please sign in to leave a comment.