Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.densy.scriptify.api.exception;

/**
* Custom exception for errors while script copy process.
*/
public class ScriptModuleCopyException extends RuntimeException {

/**
* Creates a new ScriptModuleCopyException with the specified message.
*
* @param message the detail message
*/
public ScriptModuleCopyException(String message) {
super(message);
}

/**
* Creates a new ScriptModuleCopyException with the specified message and cause.
*
* @param message the detail message
* @param cause the cause of the exception
*/
public ScriptModuleCopyException(String message, Throwable cause) {
super(message, cause);
}

/**
* Creates a new ScriptModuleCopyException with the specified cause.
*
* @param cause the cause of the exception
*/
public ScriptModuleCopyException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.densy.scriptify.api.exception;

/**
* Custom exception for errors when script module context mismatch occurs.
*/
public class ScriptModuleWrongContextException extends ScriptException {

/**
* Creates a new ScriptModuleWrongContextException with the specified message.
*
* @param expected the expected context
* @param actual the given context
*/
public ScriptModuleWrongContextException(Class<?> expected, Class<?> actual) {
super("Expected context of type " + expected.getName() + " but got " + actual.getName());
}
}
3 changes: 3 additions & 0 deletions api/src/main/java/org/densy/scriptify/api/script/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.densy.scriptify.api.exception.ScriptFunctionException;
import org.densy.scriptify.api.script.constant.ScriptConstantManager;
import org.densy.scriptify.api.script.function.ScriptFunctionManager;
import org.densy.scriptify.api.script.module.ScriptModuleManager;
import org.densy.scriptify.api.script.security.ScriptSecurityManager;

/**
Expand All @@ -21,6 +22,8 @@ public interface Script<T> {
*/
ScriptSecurityManager getSecurityManager();

ScriptModuleManager getModuleManager();

/**
* Retrieves the function manager associated with this script.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.densy.scriptify.api.script.module;

import org.densy.scriptify.api.script.module.export.ScriptExport;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnmodifiableView;

import java.util.Collection;

/**
* A module that exports elements to the script environment. Modules can be accessed via ES import (in JavaScript).
*/
public interface ScriptModule {

/**
* Module name for ES import, e.g. "@densy/mymodule".
*/
@NotNull String getName();

/**
* Gets collection of all exports in module.
*
* @return Collection with ScriptExport
*/
@UnmodifiableView Collection<ScriptExport> getExports();

/**
* Adds export to the module.
*
* @param export export to add
*/
void export(ScriptExport export);

/**
* Copies all exports from the target module that are not present in the current module.
*
* @param module target module
*/
void copy(ScriptModule module);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.densy.scriptify.api.script.module;

import org.densy.scriptify.api.script.module.export.resolver.ScriptModuleExportResolver;
import org.densy.scriptify.api.script.module.export.resolver.ScriptModuleExportResolverFactory;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;

import java.util.Map;

/**
* Manages all modules available to the script.
* The global module is always present and created automatically.
*/
public interface ScriptModuleManager {

ScriptModuleExportResolverFactory getModuleExportResolver();

void setModuleExportResolver(ScriptModuleExportResolverFactory factory);

/**
* Exports added here are available globally without import
*/
ScriptModule getGlobalModule();

@UnmodifiableView Map<String, ScriptModule> getModules();

default @Nullable ScriptModule getModule(String name) {
return this.getModules().get(name);
}

void addModule(ScriptModule module);

void removeModule(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.densy.scriptify.api.script.module.export;

/**
* Represents any exportable element from a module.
*/
public interface ScriptExport {
String getName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.densy.scriptify.api.script.module.export;

import lombok.Getter;

/**
* Universal wrapper for exporting Java values and classes.
*
* <pre>
* new ScriptValueExport("PI", 3.14) - PI available as a number
* new ScriptValueExport("MyClass", MyClass.class) - new MyClass() in JS
* new ScriptValueExport("service", myService) - access to instance methods
* </pre>
*/
@Getter
public class ScriptValueExport implements ScriptExport {

private final String name;
private final Object value;

public ScriptValueExport(String name, Object value) {
this.name = name;
this.value = value;
}

@Override
public String getName() {
return name;
}

public boolean isClass() {
return value instanceof Class<?>;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.densy.scriptify.api.script.module.export.resolver;

import org.densy.scriptify.api.script.module.export.ScriptExport;

public interface ScriptModuleExportResolver {
Object resolve(ScriptExport export);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.densy.scriptify.api.script.module.export.resolver;

import org.densy.scriptify.api.exception.ScriptModuleWrongContextException;

public interface ScriptModuleExportResolverFactory {
ScriptModuleExportResolver create(Object context) throws ScriptModuleWrongContextException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.densy.scriptify.core.script.module;

import org.densy.scriptify.api.exception.ScriptModuleCopyException;
import org.densy.scriptify.api.script.module.ScriptModule;
import org.densy.scriptify.api.script.module.export.ScriptExport;
import org.jetbrains.annotations.UnmodifiableView;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

public abstract class AbstractScriptModule implements ScriptModule {
private final Map<String, ScriptExport> exports = new LinkedHashMap<>();

@Override
public void export(ScriptExport export) {
if (export == null) {
throw new IllegalArgumentException("Export cannot be null");
}
exports.put(export.getName(), export);
}

@Override
public void copy(ScriptModule module) {
// We need to verify that the module from which we want to copy exports
// does not contain any exports with the same name as in the current
// module but with a different hash.
boolean conflicts = module.getExports().stream().anyMatch(e ->
exports.values().stream().anyMatch(existing ->
existing.getName().equals(e.getName()) &&
existing.hashCode() != e.hashCode()
)
);

if (conflicts) {
throw new ScriptModuleCopyException("The copy operation cannot be performed: both modules contain different exports with the same name");
}

module.getExports().forEach(this::export);
}

@Override
public @UnmodifiableView Collection<ScriptExport> getExports() {
return Collections.unmodifiableCollection(exports.values());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.densy.scriptify.core.script.module;

import org.jetbrains.annotations.NotNull;

public final class ScriptGlobalModule extends AbstractScriptModule {

@Override
public @NotNull String getName() {
return "global";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.densy.scriptify.core.script.module;

import org.jetbrains.annotations.NotNull;

import java.util.Objects;

public class SimpleScriptModule extends AbstractScriptModule {
private final String name;

public SimpleScriptModule(String name) {
this.name = Objects.requireNonNull(name, "Module name cannot be null");
}

@Override
public @NotNull String getName() {
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.densy.scriptify.core.script.module.export;

import lombok.Getter;
import org.densy.scriptify.api.script.constant.ScriptConstant;
import org.densy.scriptify.api.script.module.export.ScriptExport;

@Getter
public final class ScriptConstantExport implements ScriptExport {

private final ScriptConstant constant;

public ScriptConstantExport(ScriptConstant constant) {
this.constant = constant;
}

@Override
public String getName() {
return constant.getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.densy.scriptify.core.script.module.export;

import lombok.Getter;
import org.densy.scriptify.api.script.function.definition.ScriptFunctionDefinition;
import org.densy.scriptify.api.script.module.export.ScriptExport;

@Getter
public final class ScriptFunctionDefinitionExport implements ScriptExport {

private final ScriptFunctionDefinition definition;

public ScriptFunctionDefinitionExport(ScriptFunctionDefinition definition) {
this.definition = definition;
}

@Override
public String getName() {
return definition.getFunction().getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.densy.scriptify.core.script.module.export;

import lombok.Getter;
import org.densy.scriptify.api.script.function.ScriptFunction;
import org.densy.scriptify.api.script.module.export.ScriptExport;

@Getter
public final class ScriptFunctionExport implements ScriptExport {

private final ScriptFunction function;

public ScriptFunctionExport(ScriptFunction function) {
this.function = function;
}

@Override
public String getName() {
return function.getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.densy.scriptify.core.script.module.export.resolver;

import org.densy.scriptify.api.script.module.export.ScriptExport;
import org.densy.scriptify.api.script.module.export.resolver.ScriptModuleExportResolver;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public abstract class MappedModuleExportResolver implements ScriptModuleExportResolver {

private final Map<Class<?>, Function<ScriptExport, Object>> resolvers = new HashMap<>();

public <E extends ScriptExport> void map(Class<E> type, Function<E, Object> resolver) {
resolvers.put(type, export -> resolver.apply(type.cast(export)));
}

@Override
public Object resolve(ScriptExport export) {
Function<ScriptExport, Object> resolver = resolvers.get(export.getClass());
if (resolver == null) {
throw new UnsupportedOperationException("No resolver found for export " + export.getClass());
}
return resolver.apply(export);
}
}
Loading
Loading