Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions doc/changes/changes_18.0.2.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Common Module of Exasol Virtual Schemas Adapters 18.0.2, released 2026-??-??
# Common Module of Exasol Virtual Schemas Adapters 18.0.2, released 2026-06-02

Code name: Improve code quality

## Summary

## Breaking Changes
This release includes many small bugfixes and code improvements. Some methods are now deprecated and will be removed in a future release.

The release also makes interfaces `VirtualSchemaAdapter` and `AdapterFactory` `AutoCloseable`. This allows adapters to cleanup resources after processing a request. The interfaces provide a `default` implementation of `close()`, so that users of the interface don't need to change.

## Deprecations

* `Capabilities.subtractCapabilities()` is now deprecated for removal and delegates to the new pure `Capabilities.subtract()` implementation. Code that relied on the previous side effect of mutating the receiver must be adapted (#305).
* Constructor `ColumnMetadata.Builder()` is now deprecated for removal. Use `ColumnMetadata.builder()` to create a new instance (#306).
Expand All @@ -14,6 +18,10 @@ Code name: Improve code quality
* Constructor `VersionCollector()` is now deprecated for removal. Use `VersionCollector(final String path)` to create a new instance (#312)
* Methods `SqlFunctionAggregateListagg.Behavior.setTruncationType(TruncationType)` and `SqlFunctionAggregateListagg.Behavior.setTruncationFiller(SqlLiteralString)` are deprecated for removal.

## Features

* #333: Make `VirtualSchemaAdapter` and `AdapterFactory` `AutoCloseable`

## Bugfixes

* #305: Fixed `Capabilities.subtractCapabilities()` so it no longer mutates the receiver. Added the pure `Capabilities.subtract()` method.
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/com/exasol/adapter/AdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Factory that creates a {@link VirtualSchemaAdapter}
*/
public interface AdapterFactory {
public interface AdapterFactory extends AutoCloseable {
/**
* Create a new {@link VirtualSchemaAdapter}
*
Expand Down Expand Up @@ -48,4 +48,9 @@ public interface AdapterFactory {
* @return short tag for the adapter project
*/
public String getAdapterProjectShortTag();

@Override
public default void close() {
// By default, there are no resources to be closed. Adapters can override this method if needed.
}
}
15 changes: 8 additions & 7 deletions src/main/java/com/exasol/adapter/RequestDispatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ private static String processAdapterCall(final ExaMetadata metadata, final Strin
}
logVersionInformation();
logRawRequest(rawRequest);
final AdapterFactory adapterFactory = getAdapterFactory();
try (TelemetryClient telemetryClient = createTelemetryClient(adapterFactory, adapterRequest)) {
try (final AdapterFactory adapterFactory = getAdapterFactory();
TelemetryClient telemetryClient = createTelemetryClient(adapterFactory, adapterRequest)) {
final AdapterContext context = new AdapterContext(telemetryClient);
final VirtualSchemaAdapter virtualSchemaAdapter = adapterFactory.createAdapter(context);
final AdapterCallExecutor adapterCallExecutor = new AdapterCallExecutor(virtualSchemaAdapter, telemetryClient);
final String response = adapterCallExecutor.executeAdapterCall(adapterRequest, metadata);
logRawResponse(response);
return response;
try (final VirtualSchemaAdapter virtualSchemaAdapter = adapterFactory.createAdapter(context)) {
final AdapterCallExecutor adapterCallExecutor = new AdapterCallExecutor(virtualSchemaAdapter, telemetryClient);
final String response = adapterCallExecutor.executeAdapterCall(adapterRequest, metadata);
logRawResponse(response);
return response;
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/main/java/com/exasol/adapter/VirtualSchemaAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@

/**
* Interface for Virtual Schema Adapters.
*
* <p>
* This interface provides a number of handler functions for different types of requests a virtual schema adapter can
* receive from the Exasol core database.
*/
public interface VirtualSchemaAdapter {
public interface VirtualSchemaAdapter extends AutoCloseable {
/**
* Create a Virtual Schema
*
Expand Down Expand Up @@ -75,4 +74,9 @@ public GetCapabilitiesResponse getCapabilities(final ExaMetadata metadata, final
* @throws AdapterException if the adapter can't handle the request
*/
public PushDownResponse pushdown(final ExaMetadata metadata, final PushDownRequest request) throws AdapterException;
}

@Override
public default void close() {
// By default, there are no resources to be closed. Adapters can override this method if needed.
}
}
36 changes: 36 additions & 0 deletions src/test/java/com/exasol/adapter/AdapterFactoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.exasol.adapter;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import org.junit.jupiter.api.Test;

class AdapterFactoryTest {

@Test
void testDefaultCloseDoesNotThrow() {
final AdapterFactory factory = new AdapterFactoryImplementation();
assertDoesNotThrow(factory::close);
}

private final class AdapterFactoryImplementation implements AdapterFactory {
@Override
public VirtualSchemaAdapter createAdapter(final AdapterContext context) {
return null;
}

@Override
public String getAdapterVersion() {
return "test";
}

@Override
public String getAdapterName() {
return "test";
}

@Override
public String getAdapterProjectShortTag() {
return "TEST";
}
}
}
20 changes: 20 additions & 0 deletions src/test/java/com/exasol/adapter/RequestDispatcherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class RequestDispatcherTest {
@BeforeEach
void beforeEach() {
resetRootLogger();
StubAdapterFactory.resetClosed();
StubAdapter.resetClosed();
}

/**
Expand Down Expand Up @@ -121,6 +123,24 @@ void testDispatchPushDownRequest() throws AdapterException {
adapterCall(rawRequest).withResponse("{\"type\":\"pushdown\",\"sql\":\"SELECT * FROM FOOBAR\"}").verify();
}

@Test
void testFactoryIsClosedAfterDispatch() throws AdapterException {
adapterCall("{ \"type\" : \"createVirtualSchema\", " + DEFAULT_REQUEST_PARTS + "}")
.withResponse(
"{\"type\":\"createVirtualSchema\",\"schemaMetadata\":{\"tables\":[],\"adapterNotes\":\"\"}}")
.verify();
assertThat(StubAdapterFactory.wasClosed(), equalTo(true));
}

@Test
void testAdapterIsClosedAfterDispatch() throws AdapterException {
adapterCall("{ \"type\" : \"createVirtualSchema\", " + DEFAULT_REQUEST_PARTS + "}")
.withResponse(
"{\"type\":\"createVirtualSchema\",\"schemaMetadata\":{\"tables\":[],\"adapterNotes\":\"\"}}")
.verify();
assertThat(StubAdapter.wasClosed(), equalTo(true));
}

private AdapterCallVerifier adapterCall(final String rawRequest) {
return new AdapterCallVerifier(rawRequest);
}
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/com/exasol/adapter/StubAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* This class implements a stub for a VirtualSchemaAdapter
*/
public class StubAdapter implements VirtualSchemaAdapter {
private static boolean closed = false;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adapter factory is loaded via ServiceLoader in tests, so we can't inject a mock. Keeping state in a static field is the easiest solution to check if it was closed.


public StubAdapter(final AdapterContext context) {
}

Expand Down Expand Up @@ -45,4 +47,17 @@ public GetCapabilitiesResponse getCapabilities(final ExaMetadata metadata, final
public PushDownResponse pushdown(final ExaMetadata metadata, final PushDownRequest request) {
return PushDownResponse.builder().pushDownSql("SELECT * FROM FOOBAR").build();
}

@Override
public void close() {
closed = true;
}

static void resetClosed() {
closed = false;
}

static boolean wasClosed() {
return closed;
}
}
15 changes: 15 additions & 0 deletions src/test/java/com/exasol/adapter/StubAdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import static org.hamcrest.Matchers.notNullValue;

public class StubAdapterFactory implements AdapterFactory {
private static boolean closed = false;

@Override
public VirtualSchemaAdapter createAdapter(final AdapterContext context) {
assertThat(context.getTelemetryClient(), notNullValue());
Expand All @@ -24,4 +26,17 @@ public String getAdapterName() {
public String getAdapterProjectShortTag() {
return "VSSTUB";
}

@Override
public void close() {
closed = true;
}

static void resetClosed() {
closed = false;
}

static boolean wasClosed() {
return closed;
}
}
50 changes: 50 additions & 0 deletions src/test/java/com/exasol/adapter/VirtualSchemaAdapterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.exasol.adapter;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import org.junit.jupiter.api.Test;

import com.exasol.ExaMetadata;
import com.exasol.adapter.request.*;
import com.exasol.adapter.response.*;

class VirtualSchemaAdapterTest {

@Test
void testDefaultCloseDoesNotThrow() {
final VirtualSchemaAdapter adapter = new VirtualSchemaAdapterImplementation();
assertDoesNotThrow(adapter::close);
}

private final class VirtualSchemaAdapterImplementation implements VirtualSchemaAdapter {
@Override
public CreateVirtualSchemaResponse createVirtualSchema(final ExaMetadata metadata, final CreateVirtualSchemaRequest request) {
return null;
}

@Override
public DropVirtualSchemaResponse dropVirtualSchema(final ExaMetadata metadata, final DropVirtualSchemaRequest request) {
return null;
}

@Override
public RefreshResponse refresh(final ExaMetadata metadata, final RefreshRequest request) {
return null;
}

@Override
public SetPropertiesResponse setProperties(final ExaMetadata metadata, final SetPropertiesRequest request) {
return null;
}

@Override
public GetCapabilitiesResponse getCapabilities(final ExaMetadata metadata, final GetCapabilitiesRequest request) {
return null;
}

@Override
public PushDownResponse pushdown(final ExaMetadata metadata, final PushDownRequest request) {
return null;
}
}
}