Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
it.uniroma2.art.semanticturkey.customservice.CustomServiceHandlerMapping Maven / Gradle / Ivy
Go to download
The set of core services bundled with the default Semantic Turkey XPI
package it.uniroma2.art.semanticturkey.customservice;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import it.uniroma2.art.semanticturkey.pf4j.events.AllPluginsInitialized;
import it.uniroma2.art.semanticturkey.services.STServiceAdapter;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.rdf4j.model.BNode;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.MoreObjects;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import it.uniroma2.art.semanticturkey.config.ConfigurationNotFoundException;
import it.uniroma2.art.semanticturkey.config.InvalidConfigurationException;
import it.uniroma2.art.semanticturkey.config.customservice.CustomService;
import it.uniroma2.art.semanticturkey.config.customservice.CustomServiceDefinitionStore;
import it.uniroma2.art.semanticturkey.config.customservice.Operation;
import it.uniroma2.art.semanticturkey.config.customservice.Parameter;
import it.uniroma2.art.semanticturkey.config.customservice.Type;
import it.uniroma2.art.semanticturkey.extension.ExtensionPointManager;
import it.uniroma2.art.semanticturkey.extension.NoSuchConfigurationManager;
import it.uniroma2.art.semanticturkey.extension.NoSuchExtensionException;
import it.uniroma2.art.semanticturkey.extension.extpts.customservice.CustomServiceBackend;
import it.uniroma2.art.semanticturkey.properties.STPropertiesManager;
import it.uniroma2.art.semanticturkey.properties.STPropertyAccessException;
import it.uniroma2.art.semanticturkey.properties.STPropertyUpdateException;
import it.uniroma2.art.semanticturkey.properties.WrongPropertiesException;
import it.uniroma2.art.semanticturkey.services.AnnotatedValue;
import it.uniroma2.art.semanticturkey.services.Response;
import it.uniroma2.art.semanticturkey.services.STServiceContext;
import it.uniroma2.art.semanticturkey.services.annotations.Read;
import it.uniroma2.art.semanticturkey.services.annotations.RequestMethod;
import it.uniroma2.art.semanticturkey.services.annotations.STService;
import it.uniroma2.art.semanticturkey.services.annotations.STServiceOperation;
import it.uniroma2.art.semanticturkey.services.annotations.Write;
import it.uniroma2.art.semanticturkey.servlet.ServiceVocabulary.RepliesStatus;
import it.uniroma2.art.semanticturkey.servlet.ServiceVocabulary.SerializationType;
import it.uniroma2.art.semanticturkey.servlet.ServletUtilities;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.dynamic.DynamicType.Builder.MethodDefinition.ParameterDefinition.Annotatable;
import net.bytebuddy.dynamic.DynamicType.Builder.MethodDefinition.ParameterDefinition.Initial;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
/**
* A {@link HandlerMapping} that dispatches incoming requests to custom services (see
* {@link CustomServiceDefinitionStore}.
*
* @author Manuel Fiorelli
*
*/
public class CustomServiceHandlerMapping extends AbstractHandlerMapping implements Ordered {
private static final Logger logger = LoggerFactory.getLogger(CustomServiceHandlerMapping.class);
public static final String CUSTOM_SERVICES_EXTENSION_PATH = "it.uniroma2.art.semanticturkey/st-custom-services";
public static final String CUSTOM_SERVICES_URL_PREFIX = CUSTOM_SERVICES_EXTENSION_PATH + "/";
@Autowired
private ExtensionPointManager exptManager;
@Autowired
private STServiceContext stServiceContext;
@Autowired
private ConfigurableListableBeanFactory context;
static class DelegateRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private List handlers;
public DelegateRequestMappingHandlerMapping(List handlers) {
this.handlers = handlers;
}
protected void initHandlerMethods() {
for (Object h : this.handlers) {
detectHandlerMethods(h);
}
handlerMethodsInitialized(getHandlerMethods());
}
@Override
public HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
return super.getHandlerInternal(request);
}
}
private ReadWriteLock lock = new ReentrantReadWriteLock();
private DelegateRequestMappingHandlerMapping delegateMapping;
private Map customServiceHandlers = new HashMap<>();
private Multimap customServiceNames2IDs = HashMultimap.create();
@PostConstruct
public void init() throws NoSuchConfigurationManager {
setDelegateMappingInternal();
}
@EventListener
public void onAllPluginsInitialized(AllPluginsInitialized event) {
try {
initializeFromStoredCustomServices();
} catch (NoSuchConfigurationManager e) {
logger.error("An exception occurred when initializing custom services", e);
}
}
public void initializeFromStoredCustomServices() throws NoSuchConfigurationManager {
Lock wlock = lock.writeLock();
try {
wlock.lock();
CustomServiceDefinitionStore cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
// temporary multimap to spot conflicting services
customServiceNames2IDs = HashMultimap.create();
for (String customServiceCfgID : cs.getSystemConfigurationIdentifiers()) {
try {
CustomService customServiceCfg = cs.getSystemConfiguration(customServiceCfgID);
Object handler = buildCustomServiceHandler(customServiceCfgID, customServiceCfg);
customServiceHandlers.put(customServiceCfgID, handler);
customServiceNames2IDs.put(customServiceCfg.name, customServiceCfgID);
} catch (Exception e) {
logger.error(" exception occurred when parsing the custom service: " + customServiceCfgID,
e);
}
}
Iterator>> it = customServiceNames2IDs.asMap().entrySet()
.iterator();
while (it.hasNext()) {
Entry> serviceName2IDs = it.next();
String serviceName = serviceName2IDs.getKey();
Collection serviceIDs = serviceName2IDs.getValue();
if (serviceIDs.size() > 1) {
logger.error("Custom services {} use the same service name {}. Not loaded.", serviceIDs,
serviceName);
}
}
setDelegateMappingInternal();
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public Collection getCustomServiceIdentifiers() {
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException("Unable to find the configuration manager for custom services",
e);
}
return cs.getSystemConfigurationIdentifiers();
}
public CustomService getCustomService(String id) throws STPropertyAccessException {
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException("Unable to find the configuration manager for custom services",
e);
}
return cs.getSystemConfiguration(id);
}
public void registerCustomService(String customServiceCfgID) throws STPropertyAccessException,
WrongPropertiesException, InstantiationException, IllegalAccessException, SchemaException,
IllegalArgumentException, NoSuchExtensionException, InvalidConfigurationException, DuplicateName {
Lock wlock = lock.writeLock();
try {
wlock.lock();
CustomServiceDefinitionStore cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
CustomService customServiceCfg = cs.getSystemConfiguration(customServiceCfgID);
// build
Object handler = buildCustomServiceHandler(customServiceCfgID, customServiceCfg);
// checks uniqueness of custom service name
Collection conflictingCustomServiceIDs = customServiceNames2IDs.get(customServiceCfg.name)
.stream().filter(id -> !id.equals(customServiceCfgID)).collect(Collectors.toList());
if (!conflictingCustomServiceIDs.isEmpty()) {
throw new DuplicateName("the custom service '" + customServiceCfgID
+ "' uses the service name '" + customServiceCfg.name
+ "' already used by the custom service " + conflictingCustomServiceIDs);
}
// then, finalize the registration (which is unlikely to fail)
customServiceHandlers.put(customServiceCfgID, handler);
setDelegateMappingInternal();
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException("Unable to find the configuration manager for custom services",
e);
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public void registerCustomService(String customServiceCfgID, ObjectNode customServiceDefinitiondefinition,
boolean overwrite) throws STPropertyAccessException, IOException, WrongPropertiesException,
STPropertyUpdateException, InstantiationException, IllegalAccessException, SchemaException,
IllegalArgumentException, NoSuchExtensionException, InvalidConfigurationException,
CustomServiceException {
// parses the JSON object into an actual Configuration object
ObjectMapper mapper = STPropertiesManager.createObjectMapper(exptManager);
CustomService customServiceCfg = STPropertiesManager.loadSTPropertiesFromObjectNodes(
CustomService.class, true, mapper, customServiceDefinitiondefinition);
registerCustomService(customServiceCfgID, customServiceCfg, overwrite);
}
public void registerCustomService(String customServiceCfgID, CustomService customServiceCfg,
boolean overwrite) throws STPropertyAccessException, IOException, WrongPropertiesException,
STPropertyUpdateException, InstantiationException, IllegalAccessException, SchemaException,
IllegalArgumentException, NoSuchExtensionException, InvalidConfigurationException,
CustomServiceException {
Lock wlock = lock.writeLock();
try {
wlock.lock();
CustomServiceDefinitionStore cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
// raises an exception if a custom service with the same configuration id exists and overwriting
// is disabled
if (!overwrite && cs.getSystemConfigurationIdentifiers().contains(customServiceCfgID)) {
throw new DuplicateIdException(
"A CustomService definition with id '" + customServiceCfgID + "' already exists");
}
// build
Object handler = buildCustomServiceHandler(customServiceCfgID, customServiceCfg);
// checks uniqueness of custom service name
Collection conflictingCustomServiceIDs = customServiceNames2IDs.get(customServiceCfg.name)
.stream().filter(id -> !id.equals(customServiceCfgID)).collect(Collectors.toList());
if (!conflictingCustomServiceIDs.isEmpty()) {
throw new DuplicateName("the custom service '" + customServiceCfgID
+ "' uses the service name '" + customServiceCfg.name
+ "' already used by the custom service " + conflictingCustomServiceIDs);
}
// first, try to store the configuration
cs.storeSystemConfiguration(customServiceCfgID, customServiceCfg);
// then, finalize the registration (which is unlikely to fail)
customServiceHandlers.put(customServiceCfgID, handler);
customServiceNames2IDs.put(customServiceCfg.name, customServiceCfgID);
setDelegateMappingInternal();
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException("Unable to find the configuration manager for custom services",
e);
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public void unregisterCustomService(String customServiceCfgID) throws ConfigurationNotFoundException {
Lock wlock = lock.writeLock();
try {
wlock.lock();
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException(
"Unable to find the configuration manager for custom services", e);
}
cs.deleteSystemConfiguration(customServiceCfgID);
Object removedMapping = customServiceHandlers.remove(customServiceCfgID);
customServiceNames2IDs.values().remove(customServiceCfgID);
if (removedMapping != null) {
setDelegateMappingInternal();
}
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public void addOperationToCustomeService(String id, ObjectNode operationDefinition)
throws STPropertyAccessException, IOException, WrongPropertiesException, InstantiationException,
IllegalAccessException, SchemaException, IllegalArgumentException, NoSuchExtensionException,
STPropertyUpdateException, InvalidConfigurationException, CustomServiceException {
Lock wlock = lock.writeLock();
try {
wlock.lock();
ObjectMapper mapper = STPropertiesManager.createObjectMapper(exptManager);
Operation op = mapper.treeToValue(operationDefinition, Operation.class);
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException(
"Unable to find the configuration manager for custom services", e);
}
CustomService customService = cs.getSystemConfiguration(id);
List oldOps = customService.operations;
if (oldOps != null) {
customService.operations = new ArrayList<>(oldOps.size() + 1);
customService.operations.addAll(oldOps);
customService.operations.add(op);
} else {
customService.operations = Lists.newArrayList(op);
}
registerCustomService(id, customService, true);
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public void udpateOperationInCustomeService(String id, ObjectNode operationDefinition,
String oldOperationName)
throws STPropertyAccessException, IOException, WrongPropertiesException, InstantiationException,
IllegalAccessException, SchemaException, IllegalArgumentException, NoSuchExtensionException,
STPropertyUpdateException, InvalidConfigurationException, CustomServiceException {
Lock wlock = lock.writeLock();
try {
wlock.lock();
ObjectMapper mapper = STPropertiesManager.createObjectMapper(exptManager);
Operation op = mapper.treeToValue(operationDefinition, Operation.class);
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException(
"Unable to find the configuration manager for custom services", e);
}
CustomService customService = cs.getSystemConfiguration(id);
String op2replace = oldOperationName != null ? oldOperationName : op.name;
if (customService.operations != null) {
customService.operations = customService.operations.stream()
.map(eop -> Objects.equals(eop.name, op2replace) ? op : eop)
.collect(Collectors.toList());
}
registerCustomService(id, customService, true);
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
public void removeOperationFromCustomeService(String id, String operationName)
throws STPropertyAccessException, IOException, WrongPropertiesException, InstantiationException,
IllegalAccessException, SchemaException, IllegalArgumentException, NoSuchExtensionException,
STPropertyUpdateException, InvalidConfigurationException, CustomServiceException {
Lock wlock = lock.writeLock();
try {
wlock.lock();
CustomServiceDefinitionStore cs;
try {
cs = (CustomServiceDefinitionStore) exptManager
.getConfigurationManager(CustomServiceDefinitionStore.class.getName());
} catch (NoSuchConfigurationManager e) {
throw new IllegalStateException(
"Unable to find the configuration manager for custom services", e);
}
CustomService customService = cs.getSystemConfiguration(id);
List oldOps = customService.operations;
if (oldOps != null) {
customService.operations = customService.operations.stream()
.filter(eop -> !Objects.equals(eop.name, operationName)).collect(Collectors.toList());
}
registerCustomService(id, customService, true);
} finally {
if (wlock != null) {
wlock.unlock();
}
}
}
// this method should be invoked after acquiring the write lock
protected void setDelegateMappingInternal() {
// defensive copy of the argument list
delegateMapping = new DelegateRequestMappingHandlerMapping(
Lists.newArrayList(customServiceHandlers.values()));
delegateMapping.afterPropertiesSet();
}
/*
* @formatter:off
* Pattern for the recognition of authorizations.
* These are the named capturing group:
* - "area": matches the area (restricted to letters)
* - "subjfun": optionally, matches the subject as a function invocation; "subjfunpar" is the parameter
* - "subjlit": matches the subject as a a literal (exclusive with the previous)
* - "scope": optionally, matches the scope as a literal (restricted to letters)
* - "userkey": optionally, matches a key in the userResponsibility structure (restricted to letters)
* - "userlit": optionally, the value associated with the key (as word characters)
* - "userfun": optionally, the value associated with the key as a function invocation (exclusive with the previous); "usefunpar" is the parameter
* - "crudv": the operation in the CRUDV model
*
* The pattern matches unquoted authorizations:
* rdf(@typeof(#root),lexicalizations), {lang: @langOf}, R
*
* quotes should be added:
*
* 'rdf(' + @auth.typeof(#root) + ',lexicalizations)', '{lang: ''' + @auth.langOf(#label) + '''}', 'R'
* @formatter:on
*/
private Pattern AUTHORIZATION_PATTERN = Pattern.compile(
"^\\s*(? [a-z]+)(?\\(((?@typeof\\(\\s*#(?[a-z]+)\\s*\\))|(?[a-z]+))(\\s*,\\s*(?\\w+))?\\))?(\\s*,\\s*\\{\\s*(?[a-z]+)\\s*:\\s*((?\\w+)|(?(@langof\\(\\s*#(?[a-z]+)\\s*\\))))\\s*\\})?\\s*,\\s*(?[CRUDV])\\s*$",
Pattern.CASE_INSENSITIVE);
private Object buildCustomServiceHandler(String cfgID, CustomService customServiceCfg)
throws SchemaException, IllegalArgumentException, NoSuchExtensionException,
WrongPropertiesException, STPropertyAccessException, InvalidConfigurationException, IllegalAccessException {
// mimicking ordinary ST service, we have to build i) a Spring MVC controller, and ii) an @STService
// object. The controller binds the request parameters and delegates the actual implementation to the
// service
List operationDefinitions = Optional.ofNullable(customServiceCfg.operations)
.orElse(Collections.emptyList());
// build the service class
Builder> serviceClassBuilder = new ByteBuddy().subclass(STServiceAdapter.class);
serviceClassBuilder = serviceClassBuilder
.annotateType(AnnotationDescription.Builder.ofType(STService.class).build())
.defineField("stServiceContext", STServiceContext.class, Modifier.PUBLIC)
.annotateField(AnnotationDescription.Builder.ofType(Autowired.class).build());
List> backends = new ArrayList<>(operationDefinitions.size());
for (Operation operationDefinition : operationDefinitions) {
CustomServiceBackend customServiceBackend = exptManager.instantiateExtension(CustomServiceBackend.class, operationDefinition);
backends.add(ImmutablePair.of(operationDefinition, customServiceBackend));
InvocationHandler invocationHandler = customServiceBackend.createInvocationHandler();
boolean isWrite = customServiceBackend.isWrite();
String preauthorizeValue = computeAuthorizationString(operationDefinition, isWrite);
TypeDefinition returnTypeDefinition = generateTypeDefinitionFromSchema(
operationDefinition.returns);
if (isWrite) {
if (!returnTypeDefinition.equals(net.bytebuddy.description.type.TypeDescription.VOID)) {
throw new RuntimeException("Mutation operations may not return a value");
}
}
Initial> methodBuilder = serviceClassBuilder.defineMethod(operationDefinition.name,
returnTypeDefinition, Modifier.PUBLIC);
Annotatable> parameterBuilder = null;
List parameters = Optional.ofNullable(operationDefinition.parameters)
.orElse(Collections.emptyList());
for (Parameter parameterDefinition : parameters) {
parameterBuilder = MoreObjects.firstNonNull(parameterBuilder, methodBuilder).withParameter(
generateTypeDefinitionFromSchema(parameterDefinition.type), parameterDefinition.name);
}
serviceClassBuilder = MoreObjects.firstNonNull(parameterBuilder, methodBuilder)
.intercept(InvocationHandlerAdapter.of(invocationHandler))
.annotateMethod(AnnotationDescription.Builder.ofType(STServiceOperation.class)
.define("method", isWrite ? RequestMethod.POST : RequestMethod.GET).build(),
AnnotationDescription.Builder.ofType(isWrite ? Write.class : Read.class).build(),
AnnotationDescription.Builder.ofType(PreAuthorize.class)
.define("value", preauthorizeValue).build());
}
Class> serviceClass = serviceClassBuilder
.make()
.load(STServiceAdapter.class.getClassLoader(), ClassLoadingStrategy.UsingLookup.of(MethodHandles.privateLookupIn(STServiceAdapter.class, MethodHandles.lookup())))
.getLoaded();
// build a service object using the Spring context to enable dependency injection (e.g. of the service
// context), aspects, etc.
Object service = context.createBean(serviceClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
// build the controller class
Builder> controllerClassBuilder = new ByteBuddy().subclass(CustomControllerBase.class);
controllerClassBuilder = controllerClassBuilder
.annotateType(AnnotationDescription.Builder.ofType(Controller.class).build());
for (Pair confAndBackend : backends) {
Operation operationDefinition = confAndBackend.getLeft();
CustomServiceBackend backend = confAndBackend.getRight();
boolean isWrite = backend.isWrite();
TypeDefinition returnTypeDefinition = generateTypeDefinitionFromSchema(
operationDefinition.returns);
Initial> methodBuilder = controllerClassBuilder.defineMethod(operationDefinition.name,
isWrite ? net.bytebuddy.description.type.TypeDescription.Generic.Builder
.parameterizedType(HttpEntity.class, String.class).build()
: net.bytebuddy.description.type.TypeDescription.Generic.Builder
.parameterizedType(
net.bytebuddy.description.type.TypeDescription.Generic.Builder
.rawType(Response.class).build().asErasure(),
returnTypeDefinition)
.build(),
Modifier.PUBLIC);
Annotatable> parameterBuilder = null;
List parameters = Optional.ofNullable(operationDefinition.parameters)
.orElse(Collections.emptyList());
for (Parameter parameterDefinition : parameters) {
parameterBuilder = MoreObjects.firstNonNull(parameterBuilder, methodBuilder)
.withParameter(generateTypeDefinitionFromSchema(parameterDefinition.type),
parameterDefinition.name)
.annotateParameter(AnnotationDescription.Builder.ofType(RequestParam.class)
.define("value", parameterDefinition.name)
.define("required", parameterDefinition.required).build());
}
controllerClassBuilder = MoreObjects.firstNonNull(parameterBuilder, methodBuilder)
.intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method m = Arrays.stream(service.getClass().getMethods())
.filter(method2 -> method2.getName().equals(operationDefinition.name))
.findAny().get();
Object out;
try {
out = m.invoke(service, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
if (isWrite) {
return new HttpEntity<>(ServletUtilities.getService()
.createReplyResponse(operationDefinition.name, RepliesStatus.ok,
SerializationType.json)
.getResponseContent(), new HttpHeaders());
} else {
return new Response<>(out);
}
}
}))
.annotateMethod(AnnotationDescription.Builder.ofType(RequestMapping.class)
.defineArray("value",
CUSTOM_SERVICES_URL_PREFIX + customServiceCfg.name + "/"
+ operationDefinition.name)
.defineEnumerationArray("method",
org.springframework.web.bind.annotation.RequestMethod.class,
isWrite ? org.springframework.web.bind.annotation.RequestMethod.POST
: org.springframework.web.bind.annotation.RequestMethod.GET)
.defineArray("produces", "application/json;charset=UTF-8").build())
.annotateMethod(AnnotationDescription.Builder.ofType(ResponseBody.class).build());
}
Class extends Object> controllerClass = controllerClassBuilder
.make()
.load(CustomControllerBase.class.getClassLoader(), ClassLoadingStrategy.UsingLookup.of(MethodHandles.privateLookupIn(CustomControllerBase.class, MethodHandles.lookup())))
.getLoaded();
Object controller = context.createBean(controllerClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,
true);
return controller;
}
protected String computeAuthorizationString(Operation operationDefinition, boolean isWrite)
throws RuntimeException {
String preauthorizeValue;
if (StringUtils.isNoneBlank(operationDefinition.authorization)) {
Matcher m = AUTHORIZATION_PATTERN.matcher(operationDefinition.authorization);
if (!m.find()) {
throw new RuntimeException("Invalid authorization string");
}
StringBuilder sb = new StringBuilder();
sb.append("@auth.isAuthorized(");
sb.append("'");
sb.append(m.group("area"));
if (m.group("subj") != null) {
sb.append("(");
if (m.group("subjlit") != null) {
sb.append(m.group("subjlit"));
} else {
sb.append("' +");
sb.append("@auth." + m.group("subjfun").substring(1)); // removes leading @
sb.append("+ '");
}
if (m.group("scope") != null) {
sb.append(", ").append(m.group("scope"));
}
sb.append(")");
}
sb.append("'");
if (m.group("userkey") != null) {
sb.append(", '{" + m.group("userkey") + ": ");
if (m.group("userlit") != null) {
sb.append("''").append(m.group("userlit")).append("''");
} else {
sb.append("'''").append(" + @auth." + m.group("userfun").substring(1)).append(" + '''");
}
sb.append("}'");
}
String crudv = m.group("crudv");
if (isWrite) {
if (!crudv.chars().allMatch(c -> c == 'C' || c == 'U' || c == 'D')) {
throw new IllegalArgumentException(
"Invalid CRUD operations associated with a write service operation");
}
} else {
if (!Objects.equals(crudv, "R")) {
throw new IllegalArgumentException(
"Invalid CRUD operations associated with a read service operation");
}
}
sb.append(", '").append(crudv).append("'");
sb.append(")");
preauthorizeValue = sb.toString();
} else {
preauthorizeValue = "@auth.isAuthorized('rdf(code)', " + (isWrite ? "'CUD'" : "'R'") + ")";
}
return preauthorizeValue;
}
protected TypeDefinition generateTypeDefinitionFromSchema(Type typeDescription) throws SchemaException {
if ("AnnotatedValue".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder
.parameterizedType(AnnotatedValue.class, Value.class).build();
} else if ("java.lang.String".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.STRING;
} else if ("boolean".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Boolean.class)
.build();
} else if ("integer".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Integer.class)
.build();
} else if ("long".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Long.class).build();
} else if ("float".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Float.class)
.build();
} else if ("double".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Double.class)
.build();
} else if ("List".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder
.parameterizedType(TypeDefinition.Sort.describe(List.class).asErasure(),
typeDescription.getTypeArguments().stream()
.map(this::generateTypeDefinitionFromSchema).collect(Collectors.toList()))
.build();
} else if ("IRI".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(IRI.class).build();
} else if ("Literal".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Literal.class)
.build();
} else if ("Resource".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Resource.class)
.build();
} else if ("BNode".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(BNode.class)
.build();
} else if ("RDFValue".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder.rawType(Value.class)
.build();
} else if ("TupleQueryResult".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.Generic.Builder
.rawType(TupleQueryResult.class).build();
} else if ("void".equals(typeDescription.getName())) {
return net.bytebuddy.description.type.TypeDescription.VOID;
} else {
throw new SchemaException("Unknown type '" + typeDescription.getName());
}
}
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
Lock rlock = lock.readLock();
try {
rlock.lock();
return delegateMapping.getHandlerInternal(request);
} finally {
if (rlock != null) {
rlock.unlock();
}
}
}
public boolean isMapped(String id) {
Lock rlock = lock.readLock();
try {
rlock.lock();
return customServiceHandlers.containsKey(id);
} finally {
if (rlock != null) {
rlock.unlock();
}
}
}
public Object getHandler(String serviceName) {
String id = getServiceId(serviceName);
return id != null ? customServiceHandlers.get(id) : null;
}
public String getServiceId(String serviceName) {
return Iterables.getFirst(customServiceNames2IDs.get(serviceName), null);
}
}