diff options
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.java | 137 |
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 @@ | |||
1 | package tools.refinery.language.web.xtext.servlet; | ||
2 | |||
3 | import java.io.IOException; | ||
4 | |||
5 | import org.eclipse.emf.common.util.URI; | ||
6 | import org.eclipse.xtext.resource.IResourceServiceProvider; | ||
7 | import org.eclipse.xtext.web.server.IServiceResult; | ||
8 | import org.eclipse.xtext.web.server.ISession; | ||
9 | import org.eclipse.xtext.web.server.InvalidRequestException; | ||
10 | import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException; | ||
11 | import org.eclipse.xtext.web.server.ServiceConflictResult; | ||
12 | import org.eclipse.xtext.web.server.XtextServiceDispatcher; | ||
13 | import org.eclipse.xtext.web.server.contentassist.ContentAssistResult; | ||
14 | import org.eclipse.xtext.web.server.formatting.FormattingResult; | ||
15 | import org.eclipse.xtext.web.server.hover.HoverResult; | ||
16 | import org.eclipse.xtext.web.server.model.DocumentStateResult; | ||
17 | import org.eclipse.xtext.web.server.occurrences.OccurrencesResult; | ||
18 | import org.eclipse.xtext.web.server.persistence.ResourceContentResult; | ||
19 | |||
20 | import com.google.common.base.Strings; | ||
21 | import com.google.inject.Injector; | ||
22 | |||
23 | public 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 | } | ||