Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6d48bcf
Remove UriService and related components
renczesstefan Jun 17, 2025
af13957
Add evaluateRules method to PetriNetService
renczesstefan Jun 17, 2025
5ae20f5
Fix typo in variable name causing incorrect folder creation
renczesstefan Jun 17, 2025
83ce147
Add annotations and domain models for plugin architecture
renczesstefan Jun 20, 2025
9baa073
Add PluginRegistrationConfiguration interface
renczesstefan Jun 20, 2025
0a0dd9a
- added new return type
renczesstefan Jun 20, 2025
f100480
Add plugin support framework with injection capability
renczesstefan Jun 20, 2025
a6f0634
Add plugin support framework with injection capability
renczesstefan Jun 20, 2025
be67be2
Remove EntryPointLoaderService interface
renczesstefan Jun 20, 2025
13ca6b0
Refactor plugin registration to use ApplicationContext.
renczesstefan Jun 20, 2025
fa4153e
Set plugin version dynamically from configuration
renczesstefan Jun 20, 2025
9a759d7
- implemented PluginService
renczesstefan Jun 20, 2025
e7e98d7
Add PluginHolder to ActionDelegate initialization
renczesstefan Jun 20, 2025
3cd9c0e
Refactor PluginInjector and PluginRegistrationConfiguration
tuplle Jun 21, 2025
53de537
Add annotations for ListenerFilter
tuplle Jun 21, 2025
30584cb
Merge pull request #319 from netgrif/NAE-2129
machacjozef Jun 21, 2025
4c508f6
Merge branch 'release/7.0.0-rev2' into uri_removal
machacjozef Jun 23, 2025
208238e
[NAE-2125] Remove URI service usage from admin and menu items
machacjozef Jun 23, 2025
96b38c1
Refactor `attributeId` to `value` in `MenuItemConstants`
renczesstefan Jun 23, 2025
d2424e8
Add getter and setter for 'path' in MenuItemBody
renczesstefan Jun 23, 2025
6d3ad8a
Handle null PetriNet imports gracefully in ImportHelper
renczesstefan Jun 23, 2025
f0c23d0
Refactor node path creation logic in ActionDelegate
renczesstefan Jun 24, 2025
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.netgrif.application.engine.plugin

import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService
import com.netgrif.application.engine.objects.plugin.domain.EntryPoint
import com.netgrif.application.engine.objects.plugin.domain.Method
import com.netgrif.application.engine.objects.plugin.domain.Plugin
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate
import com.netgrif.application.engine.plugin.meta.EntryPointMeta
import com.netgrif.application.engine.plugin.meta.PluginHolder
import com.netgrif.application.engine.plugin.meta.PluginMeta
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

/**
* Component responsible for injecting plugin entry points and methods into
* the application's meta-class system at runtime. Uses Groovy's metaClass
* mechanism to dynamically add closures that delegate calls to PluginService.
*
* @see ActionDelegate
* @see PluginService
*/
@Component
class PluginInjector {

/**
* Service used to invoke methods on the injected plugins.
*/
@Autowired
protected PluginService pluginService

/**
* Injects the provided plugin into the application's meta-class system.
* This will allow calls to plugin entry points and methods via dynamic
* properties on {@link PluginHolder}.
*
* @param plugin the Plugin instance to be injected
*/
void inject(Plugin plugin) {
updateMetaClasses(plugin)
}

/**
* Updates meta-class definitions for the given plugin by registering
* each entry point and its methods as closures. Each generated closure
* delegates invocation to the {@link PluginService}.
*
* @param plugin the Plugin instance whose entry points and methods
* are to be exposed dynamically
*/
protected void updateMetaClasses(Plugin plugin) {
def pluginMeta = new PluginMeta()

plugin.entryPoints.values().each { EntryPoint ep ->
def epMeta = new EntryPointMeta()

ep.methods.values().each { Method method ->
/**
* Dynamically generated method closure for entry point invocation.
*
* @param args variable-length list of Serializable arguments
* @return the result returned by PluginService.call(...)
*/
epMeta.metaClass."${method.name}" = { Serializable... args ->
pluginService.call(plugin.identifier, ep.name, method.name, args)
}
}

pluginMeta.metaClass."${ep.name}" = epMeta
}

PluginHolder.metaClass."${plugin.name}" = pluginMeta
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.netgrif.application.engine.plugin.meta

/**
* Class, that has modified meta class and is injected into
* {@link com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate}. No class-attributes needed.
* */
class EntryPointMeta {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.netgrif.application.engine.plugin.meta;


class PluginHolder {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.netgrif.application.engine.plugin.meta


class PluginMeta {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
import com.netgrif.application.engine.petrinet.service.interfaces.IUriService
import com.netgrif.application.engine.startup.runner.SuperCreatorRunner
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import com.netgrif.application.engine.workflow.service.interfaces.IDataService
Expand Down Expand Up @@ -91,9 +90,6 @@ class ImportHelper {
@Autowired
private ProcessRoleService processRoleService

@Autowired
private IUriService uriService

private final ClassLoader loader = ImportHelper.getClassLoader()


Expand All @@ -113,14 +109,19 @@ class ImportHelper {
return authorityService.getOrCreate(name)
}

Optional<PetriNet> createNet(String fileName, String release, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
return createNet(fileName, VersionType.valueOf(release.trim().toUpperCase()), author, uriNodeId)
Optional<PetriNet> createNet(String fileName, String release, LoggedUser author = userService.transformToLoggedUser(userService.getSystem())) {
return createNet(fileName, VersionType.valueOf(release.trim().toUpperCase()), author)
}

Optional<PetriNet> createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
Optional<PetriNet> createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem())) {
InputStream netStream = new ClassPathResource("petriNets/$fileName" as String).inputStream
PetriNet petriNet = petriNetService.importPetriNet(netStream, release, author, uriNodeId).getNet()
log.info("Imported '${petriNet?.title?.defaultValue}' ['${petriNet?.identifier}', ${petriNet?.stringId}]")
def outcome = petriNetService.importPetriNet(netStream, release, author)
PetriNet petriNet = outcome.getNet()
if (petriNet == null) {
log.warn("Import of [$fileName] produced no PetriNet object")
return Optional.empty()
}
log.info("Imported '${petriNet.title?.defaultValue}' ['${petriNet.identifier}', ${petriNet.stringId}]")
return Optional.of(petriNet)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.netgrif.application.engine;

import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class PluginServiceImpl implements PluginService {

private final ApplicationContext applicationContext;

@Override
public Object call(String pluginId, String entryPoint, String method, Serializable... args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
log.info("Executing entry point [{}] with method [{}]...", entryPoint, method);
Class<?>[] paramTypesFromRequest = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
Object bean = applicationContext.getBean(entryPoint);
Method methodToInvoke = findMethod(bean, method, paramTypesFromRequest);
return methodToInvoke.invoke(bean, Arrays.stream(args).toArray());
}

private Method findMethod(Object bean, String methodToExecute, Class<?>[] requestParamTypes)
throws NoSuchMethodException, IllegalArgumentException {
try {
return bean.getClass().getMethod(methodToExecute, requestParamTypes);
} catch (NoSuchMethodException e) {
return findMethodWithSuperClassParams(bean, methodToExecute, requestParamTypes, e);
}
}

private Method findMethodWithSuperClassParams(Object bean, String methodToExecute, Class<?>[] requestParamTypes,
NoSuchMethodException caughtException)
throws NoSuchMethodException, IllegalArgumentException {
Class<?> cls = bean.getClass();
Method[] methods = cls.getMethods();
Method methodToInvoke = null;
outerLoop: for (Method method : methods) {
if (!methodToExecute.equals(method.getName())) {
continue;
}

Class<?>[] paramTypes = method.getParameterTypes();
int requestParamsLen = requestParamTypes.length;
int paramsLen = paramTypes.length;

if (requestParamsLen == 0 && paramsLen == 0) {
methodToInvoke = method;
break;
} else if (paramsLen == 0 || paramsLen != requestParamsLen) {
continue;
}

for (int i = 0; i < requestParamTypes.length; ++i) {
if (!paramTypes[i].isAssignableFrom(requestParamTypes[i])) {
continue outerLoop;
}
}

if (methodToInvoke != null) {
throw new IllegalArgumentException(String.format("Method %s is ambiguous for the param types %s",
methodToExecute, Arrays.toString(requestParamTypes)));
}
methodToInvoke = method;
}

if (methodToInvoke == null) {
throw caughtException;
} else {
return methodToInvoke;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,6 @@ public long count(List<CaseSearchRequest> requests, LoggedUser user, Locale loca
}
}

public String findUriNodeId(Case aCase) {
if (aCase == null) {
return null;
}
ElasticCase elasticCase = repository.findByStringId(aCase.getStringId());
if (elasticCase == null) {
log.warn("[" + aCase.getStringId() + "] Case with id [" + aCase.getStringId() + "] is not indexed.");
return null;
}

return elasticCase.getUriNodeId();
}

protected NativeQuery buildQuery(List<CaseSearchRequest> requests, LoggedUser user, Pageable pageable, Locale locale, Boolean isIntersection) {
List<BoolQuery.Builder> singleQueries = requests.stream().map(request -> buildSingleQuery(request, user, locale)).collect(Collectors.toList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,4 @@ public interface IElasticCaseService {
void remove(String caseId);

void removeByPetriNetId(String processId);

String findUriNodeId(Case aCase);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import com.netgrif.application.engine.objects.petrinet.domain.throwable.MissingPetriNetMetaDataException;
import com.netgrif.application.engine.objects.petrinet.domain.version.Version;
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
import com.netgrif.application.engine.petrinet.service.interfaces.IUriService;
import com.netgrif.application.engine.petrinet.web.responsebodies.*;
import com.netgrif.application.engine.objects.workflow.domain.Case;
import com.netgrif.application.engine.workflow.domain.FileStorageConfiguration;
Expand Down Expand Up @@ -128,9 +127,6 @@ public class PetriNetService implements IPetriNetService {
@Autowired
protected IElasticPetriNetMappingService petriNetMappingService;

@Autowired
protected IUriService uriService;

protected ApplicationEventPublisher publisher;

protected IElasticPetriNetService elasticPetriNetService;
Expand Down Expand Up @@ -184,36 +180,19 @@ public List<PetriNet> get(List<String> petriNetIds) {
return self.get(petriNetIds.stream().map(ObjectId::new).collect(Collectors.toList()));
}


@Override
@Deprecated
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author, uriService.getDefault().getStringId());
}

@Override
@Deprecated
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser author, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author, uriNodeId);
return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author);
}

@Override
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, releaseType, author, uriService.getDefault().getStringId());
return importPetriNet(xmlFile, releaseType, author, new HashMap<>());
}

@Override
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, Map<String, String> params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, releaseType, author, uriService.getDefault().getStringId(), params);
}

@Override
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, releaseType, author, uriNodeId, new HashMap<>());
}

@Override
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, String uriNodeId, Map<String, String> params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
ImportPetriNetEventOutcome outcome = new ImportPetriNetEventOutcome();
ByteArrayOutputStream xmlCopy = new ByteArrayOutputStream();
IOUtils.copy(xmlFile, xmlCopy);
Expand All @@ -222,7 +201,6 @@ public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionTyp
return outcome;
}
PetriNet net = imported.get();
net.setUriNodeId(uriNodeId);

PetriNet existingNet = getNewestVersionByIdentifier(net.getIdentifier());
if (existingNet != null) {
Expand All @@ -245,13 +223,6 @@ public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionTyp
return outcome;
}

private ImportPetriNetEventOutcome addMessageToOutcome(PetriNet net, ProcessEventType type, ImportPetriNetEventOutcome outcome) {
if (net.getProcessEvents().containsKey(type)) {
outcome.setMessage(net.getProcessEvents().get(type).getMessage());
}
return outcome;
}

protected void evaluateRules(Event event) {
publisher.publishEvent(event);

Expand Down Expand Up @@ -301,16 +272,9 @@ public List<PetriNet> getByIdentifier(String identifier) {
return nets;
}

@Override
public List<PetriNet> findAllByUriNodeId(String uriNodeId) {
List<PetriNet> nets = elasticPetriNetService.findAllByUriNodeId(uriNodeId);
nets.forEach(PetriNet::initializeArcs);
return nets;
}

@Override
public List<PetriNet> findAllById(List<String> ids) {
return StreamSupport.stream(repository.findAllById(ids).spliterator(), false).collect(Collectors.toList());
return new ArrayList<>(repository.findAllById(ids));
}

@Override
Expand All @@ -320,7 +284,7 @@ public PetriNet getNewestVersionByIdentifier(String identifier) {
if (nets.isEmpty()) {
return null;
}
return nets.get(0);
return nets.getFirst();
}

/**
Expand Down
Loading
Loading