Skip to content

Commit

Permalink
Abstract out Legend Engine server client into a service
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin-m-knight-gs committed Dec 7, 2023
1 parent 2d3fc72 commit ea47d50
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@
import com.fasterxml.jackson.core.StreamReadFeature;
import com.fasterxml.jackson.core.StreamWriteFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.ImmutableList;
Expand Down Expand Up @@ -83,14 +75,13 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.function.Consumer;

abstract class AbstractLSPGrammarExtension implements LegendLSPGrammarExtension
{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLSPGrammarExtension.class);

private static final String ENGINE_SERVER_URL = System.getProperty("legend.engine.server.url");

private static final String RUN_TESTS_COMMAND_ID = "legend.testable.runTests";
private static final String RUN_TESTS_COMMAND_TITLE = "Run tests";

Expand All @@ -107,6 +98,7 @@ abstract class AbstractLSPGrammarExtension implements LegendLSPGrammarExtension

private final Map<String, ? extends TestableRunnerExtension> testableRunners = TestableRunnerExtensionLoader.getClassifierPathToTestableRunnerMap();
private final Map<Class<? extends PackageableElement>, String> classToClassifier = ProtocolToClassifierPathLoader.getProtocolClassToClassifierMap();
private final LegendEngineServerClient engineServerClient = newEngineServerClient();

private JsonMapper protocolMapper;
private PureGrammarComposer composer;
Expand Down Expand Up @@ -534,7 +526,7 @@ private JsonMapper getProtocolMapper()

protected boolean isEngineServerConfigured()
{
return ENGINE_SERVER_URL != null;
return this.engineServerClient.isServerConfigured();
}

protected <T> T postEngineServer(String path, Object payload, Class<T> responseType)
Expand All @@ -543,26 +535,14 @@ protected <T> T postEngineServer(String path, Object payload, Class<T> responseT
{
throw new IllegalStateException("Engine server is not configured");
}
String url = ENGINE_SERVER_URL + path;

try
{
JsonMapper json = getProtocolMapper();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(json.writeValueAsString(payload), ContentType.APPLICATION_JSON));

try (CloseableHttpClient client = newHttpClient();
CloseableHttpResponse response = client.execute(httpPost))
JsonMapper mapper = getProtocolMapper();
String payloadJson = mapper.writeValueAsString(payload);
try (InputStream stream = this.engineServerClient.post(path, payloadJson))
{
HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() != 200)
{
String responseString = EntityUtils.toString(entity);
throw new RuntimeException("Engine server responded to " + url + " with status: " + response.getStatusLine().getStatusCode() + "\nresponse: " + responseString);
}
try (InputStream stream = entity.getContent())
{
return json.readValue(stream, responseType);
}
return mapper.readValue(stream, responseType);
}
}
catch (IOException e)
Expand All @@ -588,12 +568,6 @@ private PureGrammarComposer getComposer()
}
}

private CloseableHttpClient newHttpClient()
{
// TODO configure the client properly
return HttpClientBuilder.create().build();
}

protected LegendDeclaration getDeclaration(PackageableElement element)
{
String path = element.getPath();
Expand Down Expand Up @@ -677,6 +651,18 @@ protected static TextInterval toLocation(SourceInformation sourceInfo)
return TextInterval.newInterval(sourceInfo.startLine - 1, sourceInfo.startColumn - 1, sourceInfo.endLine - 1, sourceInfo.endColumn - 1);
}

private static LegendEngineServerClient newEngineServerClient()
{
for (LegendEngineServerClient client : ServiceLoader.load(LegendEngineServerClient.class))
{
if (client.isServerConfigured())
{
return client;
}
}
return new DefaultLegendEngineServerClient();
}

protected static class Result<T>
{
protected final T result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2023 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.engine.ide.lsp.extension;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;

class DefaultLegendEngineServerClient implements LegendEngineServerClient
{
private final String engineServerUrl = System.getProperty("legend.engine.server.url");

@Override
public boolean isServerConfigured()
{
return this.engineServerUrl != null;
}

@Override
public InputStream post(String path, String payload, String contentType)
{
return post(path, new StringEntity(payload, contentType));
}

private InputStream post(String path, HttpEntity payload)
{
if (!isServerConfigured())
{
throw new IllegalStateException("Engine server is not configured");
}
String url = buildUrl(path);
try
{
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(payload);

try (CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse response = client.execute(httpPost))
{
HttpEntity entity = response.getEntity();
if ((response.getStatusLine().getStatusCode() / 100) != 2)
{
String responseString = EntityUtils.toString(entity);
throw new RuntimeException("Engine server responded to " + url + " with status: " + response.getStatusLine().getStatusCode() + "\nresponse: " + responseString);
}
return entity.getContent();
}
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
}

private String buildUrl(String path)
{
return this.engineServerUrl +
(this.engineServerUrl.endsWith("/") ?
(path.startsWith("/") ? path.substring(1) : path) :
(path.startsWith("/") ? path : ("/" + path)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2023 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.engine.ide.lsp.extension;

import java.io.InputStream;

public interface LegendEngineServerClient
{
default boolean isServerConfigured()
{
return false;
}

default InputStream post(String path, String payload)
{
return post(path, payload, "application/json");
}

InputStream post(String path, String payload, String contentType);
}

0 comments on commit ea47d50

Please sign in to comment.