aboutsummaryrefslogtreecommitdiffstats
path: root/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java
diff options
context:
space:
mode:
Diffstat (limited to 'language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java')
-rw-r--r--language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java137
1 files changed, 137 insertions, 0 deletions
diff --git a/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java b/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java
new file mode 100644
index 00000000..08687097
--- /dev/null
+++ b/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/TransactionExecutor.java
@@ -0,0 +1,137 @@
1package tools.refinery.language.web.xtext.servlet;
2
3import java.io.IOException;
4
5import org.eclipse.emf.common.util.URI;
6import org.eclipse.xtext.resource.IResourceServiceProvider;
7import org.eclipse.xtext.web.server.IServiceResult;
8import org.eclipse.xtext.web.server.ISession;
9import org.eclipse.xtext.web.server.InvalidRequestException;
10import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException;
11import org.eclipse.xtext.web.server.ServiceConflictResult;
12import org.eclipse.xtext.web.server.XtextServiceDispatcher;
13import org.eclipse.xtext.web.server.contentassist.ContentAssistResult;
14import org.eclipse.xtext.web.server.formatting.FormattingResult;
15import org.eclipse.xtext.web.server.hover.HoverResult;
16import org.eclipse.xtext.web.server.model.DocumentStateResult;
17import org.eclipse.xtext.web.server.occurrences.OccurrencesResult;
18import org.eclipse.xtext.web.server.persistence.ResourceContentResult;
19
20import com.google.common.base.Strings;
21import com.google.inject.Injector;
22
23public class TransactionExecutor {
24 private final ISession session;
25
26 private final IResourceServiceProvider.Registry resourceServiceProviderRegistry;
27
28 public TransactionExecutor(ISession session, IResourceServiceProvider.Registry resourceServiceProviderRegistry) {
29 this.session = session;
30 this.resourceServiceProviderRegistry = resourceServiceProviderRegistry;
31 }
32
33 public void handleRequest(XtextWebSocketRequest request, ResponseHandler handler) throws IOException {
34 var requestData = request.getRequestData();
35 if (requestData == null || requestData.isEmpty()) {
36 // Nothing to do.
37 return;
38 }
39 int nCalls = requestData.size();
40 int lastCall = handleTransaction(request, handler);
41 for (int index = lastCall + 1; index < nCalls; index++) {
42 handler.onResponse(
43 new XtextWebSocketErrorResponse(request, index, XtextWebSocketErrorKind.TRANSACTION_CANCELLED));
44 }
45 }
46
47 protected int handleTransaction(XtextWebSocketRequest request, ResponseHandler handler) throws IOException {
48 var requestData = request.getRequestData();
49 var stateId = request.getRequiredStateId();
50 int index = 0;
51 try {
52 var injector = getInjector(request);
53 var serviceDispatcher = injector.getInstance(XtextServiceDispatcher.class);
54 int nCalls = requestData.size();
55 for (; index < nCalls; index++) {
56 var serviceContext = SimpleServiceContext.ofTransaction(session, request, stateId, index);
57 var service = serviceDispatcher.getService(serviceContext);
58 var serviceResult = service.getService().apply();
59 handler.onResponse(new XtextWebSocketOkResponse(request, index, serviceResult));
60 if (serviceResult instanceof ServiceConflictResult) {
61 break;
62 }
63 var nextStateId = getNextStateId(serviceResult);
64 if (nextStateId != null) {
65 stateId = nextStateId;
66 }
67 }
68 } catch (InvalidRequestException e) {
69 handler.onResponse(
70 new XtextWebSocketErrorResponse(request, index, XtextWebSocketErrorKind.REQUEST_ERROR, e));
71 } catch (RuntimeException e) {
72 handler.onResponse(
73 new XtextWebSocketErrorResponse(request, index, XtextWebSocketErrorKind.SERVER_ERROR, e));
74 }
75 return index;
76 }
77
78 /**
79 * Get the injector to satisfy the request in the {@code serviceContext}.
80 *
81 * Based on {@link org.eclipse.xtext.web.servlet.XtextServlet#getInjector}.
82 *
83 * @param serviceContext the Xtext service context of the request
84 * @return the injector for the Xtext language in the request
85 * @throws UnknownLanguageException if the Xtext language cannot be determined
86 */
87 protected Injector getInjector(XtextWebSocketRequest request) {
88 IResourceServiceProvider resourceServiceProvider = null;
89 var resourceName = request.getResourceName();
90 if (resourceName == null) {
91 resourceName = "";
92 }
93 var emfURI = URI.createURI(resourceName);
94 var contentType = request.getContentType();
95 if (Strings.isNullOrEmpty(contentType)) {
96 resourceServiceProvider = resourceServiceProviderRegistry.getResourceServiceProvider(emfURI);
97 if (resourceServiceProvider == null) {
98 if (emfURI.toString().isEmpty()) {
99 throw new UnknownLanguageException(
100 "Unable to identify the Xtext language: missing parameter 'resource' or 'contentType'.");
101 } else {
102 throw new UnknownLanguageException(
103 "Unable to identify the Xtext language for resource " + emfURI + ".");
104 }
105 }
106 } else {
107 resourceServiceProvider = resourceServiceProviderRegistry.getResourceServiceProvider(emfURI, contentType);
108 if (resourceServiceProvider == null) {
109 throw new UnknownLanguageException(
110 "Unable to identify the Xtext language for contentType " + contentType + ".");
111 }
112 }
113 return resourceServiceProvider.get(Injector.class);
114 }
115
116 protected String getNextStateId(IServiceResult serviceResult) {
117 if (serviceResult instanceof ContentAssistResult contentAssistResult) {
118 return contentAssistResult.getStateId();
119 }
120 if (serviceResult instanceof DocumentStateResult documentStateResult) {
121 return documentStateResult.getStateId();
122 }
123 if (serviceResult instanceof FormattingResult formattingResult) {
124 return formattingResult.getStateId();
125 }
126 if (serviceResult instanceof HoverResult hoverResult) {
127 return hoverResult.getStateId();
128 }
129 if (serviceResult instanceof OccurrencesResult occurrencesResult) {
130 return occurrencesResult.getStateId();
131 }
132 if (serviceResult instanceof ResourceContentResult resourceContentResult) {
133 return resourceContentResult.getStateId();
134 }
135 return null;
136 }
137}