Skip to content

Commit

Permalink
Refactor common SPI logic, handle SPI registrations with missing Enso…
Browse files Browse the repository at this point in the history
… library (#11722)

- Closes #11707 by filtering out SPI registrations that cannot load their corresponding Enso type.
  • Loading branch information
radeusgd authored Dec 3, 2024
1 parent 65010df commit 498b506
Show file tree
Hide file tree
Showing 34 changed files with 232 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.enso.database.DatabaseConnectionDetailsSPI;

@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class)
public class RedshiftConnectionDetailsSPI extends DatabaseConnectionDetailsSPI {
public final class RedshiftConnectionDetailsImpl extends DatabaseConnectionDetailsSPI {
@Override
protected String getModuleName() {
return "Standard.AWS.Database.Redshift.Redshift_Details";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.enso.base.enso_cloud.DataLinkSPI;

@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class)
public class S3DataLinkSPI extends DataLinkSPI {
public final class S3DataLinkImpl extends DataLinkSPI {
@Override
protected String getModuleName() {
return "Standard.AWS.S3.S3_Data_Link";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.enso.base.file_system.FileSystemSPI;

@org.openide.util.lookup.ServiceProvider(service = FileSystemSPI.class)
public class S3FileSystemSPI extends FileSystemSPI {
public final class S3FileSystemImpl extends FileSystemSPI {
@Override
protected String getModuleName() {
return "Standard.AWS.S3.S3_File";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,38 @@
package org.enso.base.enso_cloud;

import java.util.ServiceLoader;
import java.util.stream.Collectors;
import org.enso.base.polyglot.EnsoMeta;
import java.util.Objects;
import org.enso.base.spi.EnsoService;
import org.enso.base.spi.EnsoServiceLoader;
import org.graalvm.polyglot.Value;

/**
* An interface for data link parser providers. A class providing this interface can register an
* Enso type that defines how to `parse` a specific type of datalink. The `parse` method on that
* type should return a configured datalink instance that can later be `read`.
*/
public abstract class DataLinkSPI {
private static final ServiceLoader<DataLinkSPI> loader =
ServiceLoader.load(DataLinkSPI.class, DataLinkSPI.class.getClassLoader());
public abstract class DataLinkSPI extends EnsoService {
private static final EnsoServiceLoader<DataLinkSPI> loader =
EnsoServiceLoader.load(DataLinkSPI.class);

public void reload() {
loader.reload();
}

public static Value findDataLinkType(String name) {
var providers =
loader.stream().filter(provider -> provider.get().getLinkTypeName().equals(name)).toList();
if (providers.isEmpty()) {
Objects.requireNonNull(name, "name must not be null/Nothing.");
var found =
loader.findSingleProvider(provider -> name.equals(provider.getLinkTypeName()), name);
if (found == null) {
return null;
}

if (providers.size() > 1) {
var modules =
providers.stream()
.map(provider -> provider.get().getModuleName())
.collect(Collectors.joining(", "));
throw new IllegalStateException(
"Error: Multiple Data Link providers found for type: "
+ name
+ ". The clashing definitions are in the following modules: "
+ modules
+ ".");
}

return providers.get(0).get().getTypeObject();
return found.getTypeObject();
}

public Value getTypeObject() {
return EnsoMeta.getType(getModuleName(), getTypeName());
}

protected abstract String getModuleName();

protected abstract String getTypeName();

/**
* Defines the name of the data link type associated with this SPI registration.
*
* <p>This is the same value as the `type` property of the corresponding variant in
* `dataLinkSchema.json`.
*/
protected abstract String getLinkTypeName();
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.enso_cloud;

@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class)
public class EnsoFileDataLinkSPI extends DataLinkSPI {
public final class EnsoFileDataLinkImpl extends DataLinkSPI {
@Override
protected String getModuleName() {
return "Standard.Base.Enso_Cloud.Internal.Enso_File_Data_Link";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* <p>See `Enso_File.new` for more information on path resolution.
*/
@org.openide.util.lookup.ServiceProvider(service = FileSystemSPI.class)
public class EnsoPathFileSystemSPI extends FileSystemSPI {
public final class EnsoPathFileSystemImpl extends FileSystemSPI {
@Override
protected String getModuleName() {
return "Standard.Base.Enso_Cloud.Enso_File";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.file_format;

@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class)
public class ByteFormatSPI extends FileFormatSPI {
public final class ByteFileFormatImpl extends FileFormatSPI {
@Override
protected String getModuleName() {
return "Standard.Base.System.File_Format";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,34 @@
package org.enso.base.file_format;

import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import org.enso.base.polyglot.EnsoMeta;
import org.enso.base.spi.EnsoService;
import org.enso.base.spi.EnsoServiceLoader;
import org.graalvm.polyglot.Value;

public abstract class FileFormatSPI {
private static final ServiceLoader<FileFormatSPI> loader =
ServiceLoader.load(FileFormatSPI.class, FileFormatSPI.class.getClassLoader());
public abstract class FileFormatSPI extends EnsoService {
private static final EnsoServiceLoader<FileFormatSPI> loader =
EnsoServiceLoader.load(FileFormatSPI.class);

public static Value[] get_types(boolean refresh) {
public static List<Value> get_types(boolean refresh) {
if (refresh) {
loader.reload();
}
return loader.stream().map(provider -> provider.get().getTypeObject()).toArray(Value[]::new);
return loader.getTypeObjects();
}

public static Value findFormatForDataLinkSubType(String subType) {
Objects.requireNonNull(subType, "subType must not be null/Nothing.");

var providers =
loader.stream()
.filter(provider -> subType.equalsIgnoreCase(provider.get().getDataLinkFormatName()))
.toList();
if (providers.isEmpty()) {
var found =
loader.findSingleProvider(
provider -> subType.equalsIgnoreCase(provider.getDataLinkFormatName()), subType);
if (found == null) {
return null;
}

if (providers.size() > 1) {
var modules =
providers.stream()
.map(provider -> provider.get().getModuleName())
.collect(Collectors.joining(", "));
throw new IllegalStateException(
"Error: Multiple Format providers found for format: "
+ subType
+ ". The clashing definitions are in the following modules: "
+ modules
+ ".");
}

return providers.get(0).get().getTypeObject();
return found.getTypeObject();
}

public Value getTypeObject() {
return EnsoMeta.getType(getModuleName(), getTypeName());
}

protected abstract String getModuleName();

protected abstract String getTypeName();

/**
* An optional method that allows this format to be parsed as a selected format in data-links.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.file_format;

@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class)
public class JSONFormatSPI extends FileFormatSPI {
public final class JSONFileFormatImpl extends FileFormatSPI {
@Override
protected String getModuleName() {
return "Standard.Base.System.File_Format";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.file_format;

@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class)
public class TextFormatSPI extends FileFormatSPI {
public final class TextFileFormatImpl extends FileFormatSPI {
@Override
protected String getModuleName() {
return "Standard.Base.System.File_Format";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.file_format;

@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class)
public class XMLFormatSPI extends FileFormatSPI {
public final class XMLFileFormatImpl extends FileFormatSPI {
@Override
protected String getModuleName() {
return "Standard.Base.Data.XML.XML_Format";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
package org.enso.base.file_system;

import java.util.ServiceLoader;
import org.enso.base.polyglot.EnsoMeta;
import java.util.List;
import java.util.Objects;
import org.enso.base.spi.EnsoService;
import org.enso.base.spi.EnsoServiceLoader;
import org.graalvm.polyglot.Value;

public abstract class FileSystemSPI {
private static final ServiceLoader<org.enso.base.file_system.FileSystemSPI> loader =
ServiceLoader.load(
org.enso.base.file_system.FileSystemSPI.class,
org.enso.base.file_format.FileFormatSPI.class.getClassLoader());
public abstract class FileSystemSPI extends EnsoService {
private static final EnsoServiceLoader<FileSystemSPI> loader =
EnsoServiceLoader.load(FileSystemSPI.class);

public static Value get_type(String protocol, boolean refresh) {
Objects.requireNonNull(protocol, "protocol must not be null/Nothing.");

if (refresh) {
loader.reload();
}

var first =
loader.stream()
.filter(provider -> provider.get().getProtocol().equals(protocol))
.findFirst();
return first
.map(fileSystemSPIProvider -> fileSystemSPIProvider.get().getTypeObject())
.orElse(null);
var found =
loader.findSingleProvider(provider -> protocol.equals(provider.getProtocol()), protocol);
if (found == null) {
return null;
}
return found.getTypeObject();
}

public static Value[] get_types(boolean refresh) {
public static List<Value> get_types(boolean refresh) {
if (refresh) {
loader.reload();
}
return loader.stream().map(provider -> provider.get().getTypeObject()).toArray(Value[]::new);
}

public Value getTypeObject() {
return EnsoMeta.getType(getModuleName(), getTypeName());
return loader.getTypeObjects();
}

protected abstract String getModuleName();

protected abstract String getTypeName();

/**
* Defines the protocol that this file system provider is responsible for.
*
* <p>For example "enso" protocol is used for handling Enso Cloud `enso://` paths.
*/
protected abstract String getProtocol();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.enso.base.enso_cloud.DataLinkSPI;

@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class)
public class HTTPFetchDataLinkSPI extends DataLinkSPI {
public final class HTTPFetchDataLinkImpl extends DataLinkSPI {
@Override
protected String getModuleName() {
return "Standard.Base.Network.HTTP.Internal.HTTP_Fetch_Data_Link";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.enso.base.read;

@org.openide.util.lookup.ServiceProvider(service = ReadManyReturnSPI.class)
public class BaseReadManyReturnSPI extends ReadManyReturnSPI {
public final class BaseReadManyReturnImpl extends ReadManyReturnSPI {
@Override
protected String getModuleName() {
return "Standard.Base.Data.Read.Return_As";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.enso.base.read;

import java.util.ServiceLoader;
import org.enso.base.polyglot.EnsoMeta;
import java.util.List;
import org.enso.base.spi.EnsoService;
import org.enso.base.spi.EnsoServiceLoader;
import org.graalvm.polyglot.Value;

/**
Expand All @@ -13,22 +14,14 @@
* the dropdown. Registered types must provide methods `get_dropdown_options`, `resolve` and
* `make_return`. See `Standard.Base.Data.Read.Return_As` for examples.
*/
public abstract class ReadManyReturnSPI {
private static final ServiceLoader<ReadManyReturnSPI> loader =
ServiceLoader.load(ReadManyReturnSPI.class, ReadManyReturnSPI.class.getClassLoader());
public abstract class ReadManyReturnSPI extends EnsoService {
private static final EnsoServiceLoader<ReadManyReturnSPI> loader =
EnsoServiceLoader.load(ReadManyReturnSPI.class);

public static Value[] get_types(boolean refresh) {
public static List<Value> get_types(boolean refresh) {
if (refresh) {
loader.reload();
}
return loader.stream().map(provider -> provider.get().getTypeObject()).toArray(Value[]::new);
return loader.getTypeObjects();
}

public Value getTypeObject() {
return EnsoMeta.getType(getModuleName(), getTypeName());
}

protected abstract String getModuleName();

protected abstract String getTypeName();
}
Loading

0 comments on commit 498b506

Please sign in to comment.