aboutsummaryrefslogtreecommitdiffstats
path: root/language-web
diff options
context:
space:
mode:
Diffstat (limited to 'language-web')
-rw-r--r--language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java46
1 files changed, 45 insertions, 1 deletions
diff --git a/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java b/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
index 335f0636..0b417b06 100644
--- a/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
+++ b/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
@@ -1,7 +1,9 @@
1package tools.refinery.language.web.xtext.server; 1package tools.refinery.language.web.xtext.server;
2 2
3import java.lang.ref.WeakReference; 3import java.lang.ref.WeakReference;
4import java.util.ArrayList;
4import java.util.HashMap; 5import java.util.HashMap;
6import java.util.List;
5import java.util.Map; 7import java.util.Map;
6 8
7import org.eclipse.emf.common.util.URI; 9import org.eclipse.emf.common.util.URI;
@@ -13,6 +15,8 @@ import org.eclipse.xtext.web.server.ISession;
13import org.eclipse.xtext.web.server.InvalidRequestException; 15import org.eclipse.xtext.web.server.InvalidRequestException;
14import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException; 16import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException;
15import org.eclipse.xtext.web.server.XtextServiceDispatcher; 17import org.eclipse.xtext.web.server.XtextServiceDispatcher;
18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory;
16 20
17import com.google.common.base.Strings; 21import com.google.common.base.Strings;
18import com.google.inject.Injector; 22import com.google.inject.Injector;
@@ -27,6 +31,8 @@ import tools.refinery.language.web.xtext.server.push.PushWebDocument;
27import tools.refinery.language.web.xtext.servlet.SimpleServiceContext; 31import tools.refinery.language.web.xtext.servlet.SimpleServiceContext;
28 32
29public class TransactionExecutor implements IDisposable, PrecomputationListener { 33public class TransactionExecutor implements IDisposable, PrecomputationListener {
34 private static final Logger LOG = LoggerFactory.getLogger(TransactionExecutor.class);
35
30 private final ISession session; 36 private final ISession session;
31 37
32 private final IResourceServiceProvider.Registry resourceServiceProviderRegistry; 38 private final IResourceServiceProvider.Registry resourceServiceProviderRegistry;
@@ -35,6 +41,12 @@ public class TransactionExecutor implements IDisposable, PrecomputationListener
35 41
36 private ResponseHandler responseHandler; 42 private ResponseHandler responseHandler;
37 43
44 private Object callPendingLock = new Object();
45
46 private boolean callPending;
47
48 private List<XtextWebPushMessage> pendingPushMessages = new ArrayList<>();
49
38 public TransactionExecutor(ISession session, IResourceServiceProvider.Registry resourceServiceProviderRegistry) { 50 public TransactionExecutor(ISession session, IResourceServiceProvider.Registry resourceServiceProviderRegistry) {
39 this.session = session; 51 this.session = session;
40 this.resourceServiceProviderRegistry = resourceServiceProviderRegistry; 52 this.resourceServiceProviderRegistry = resourceServiceProviderRegistry;
@@ -51,6 +63,15 @@ public class TransactionExecutor implements IDisposable, PrecomputationListener
51 responseHandler.onResponse(new XtextWebOkResponse(request, new PongResult(ping))); 63 responseHandler.onResponse(new XtextWebOkResponse(request, new PongResult(ping)));
52 return; 64 return;
53 } 65 }
66 synchronized (callPendingLock) {
67 if (callPending) {
68 LOG.error("Reentrant request detected");
69 }
70 if (!pendingPushMessages.isEmpty()) {
71 LOG.error("{} push messages got stuck without a pending request", pendingPushMessages.size());
72 }
73 callPending = true;
74 }
54 try { 75 try {
55 var injector = getInjector(serviceContext); 76 var injector = getInjector(serviceContext);
56 var serviceDispatcher = injector.getInstance(XtextServiceDispatcher.class); 77 var serviceDispatcher = injector.getInstance(XtextServiceDispatcher.class);
@@ -61,13 +82,36 @@ public class TransactionExecutor implements IDisposable, PrecomputationListener
61 responseHandler.onResponse(new XtextWebErrorResponse(request, XtextWebErrorKind.REQUEST_ERROR, e)); 82 responseHandler.onResponse(new XtextWebErrorResponse(request, XtextWebErrorKind.REQUEST_ERROR, e));
62 } catch (RuntimeException e) { 83 } catch (RuntimeException e) {
63 responseHandler.onResponse(new XtextWebErrorResponse(request, XtextWebErrorKind.SERVER_ERROR, e)); 84 responseHandler.onResponse(new XtextWebErrorResponse(request, XtextWebErrorKind.SERVER_ERROR, e));
85 } finally {
86 synchronized (callPendingLock) {
87 for (var message : pendingPushMessages) {
88 try {
89 responseHandler.onResponse(message);
90 } catch (ResponseHandlerException | RuntimeException e) {
91 LOG.error("Error while flushing push message", e);
92 }
93 }
94 pendingPushMessages.clear();
95 callPending = false;
96 }
64 } 97 }
65 } 98 }
66 99
67 @Override 100 @Override
68 public void onPrecomputedServiceResult(String resourceId, String stateId, String serviceName, 101 public void onPrecomputedServiceResult(String resourceId, String stateId, String serviceName,
69 IServiceResult serviceResult) throws ResponseHandlerException { 102 IServiceResult serviceResult) throws ResponseHandlerException {
70 responseHandler.onResponse(new XtextWebPushMessage(resourceId, stateId, serviceName, serviceResult)); 103 var message = new XtextWebPushMessage(resourceId, stateId, serviceName, serviceResult);
104 synchronized (callPendingLock) {
105 // If we're currently responding to a call we must delay any push messages until
106 // the reply is sent, because push messages relating to the new state id must be
107 // sent after the response with the new state id so that the client knows about
108 // the new state when it receives the push message.
109 if (callPending) {
110 pendingPushMessages.add(message);
111 } else {
112 responseHandler.onResponse(message);
113 }
114 }
71 } 115 }
72 116
73 @Override 117 @Override