All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restheart.utils.PluginUtils Maven / Gradle / Ivy

There is a newer version: 8.1.4
Show newest version
/*-
 * ========================LICENSE_START=================================
 * restheart-commons
 * %%
 * Copyright (C) 2019 - 2024 SoftInstigate
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================LICENSE_END==================================
 */
package org.restheart.utils;

import java.lang.reflect.Type;
import java.util.Map;

import org.restheart.cache.CacheFactory;
import org.restheart.cache.LoadingCache;
import static org.restheart.exchange.PipelineInfo.PIPELINE_TYPE.SERVICE;
import org.restheart.exchange.Request;
import org.restheart.exchange.Response;
import org.restheart.plugins.ExchangeTypeResolver;
import org.restheart.plugins.InitPoint;
import org.restheart.plugins.Initializer;
import org.restheart.plugins.InterceptPoint;
import org.restheart.plugins.Interceptor;
import org.restheart.plugins.Plugin;
import org.restheart.plugins.PluginRecord;
import org.restheart.plugins.PluginsRegistry;
import org.restheart.plugins.RegisterPlugin;
import org.restheart.plugins.RegisterPlugin.MATCH_POLICY;
import org.restheart.plugins.Service;
import org.restheart.plugins.security.Authorizer;

import io.undertow.server.HttpServerExchange;

/**
 *
 * @author Andrea Di Cesare {@literal }
 */
public class PluginUtils {
    /**
     *
     * @param interceptor
     * @return the interceptPoint as defined by the @RegisterPlugin annotation if
     *         annotated or the value of the field interceptPoint if exists
     */
    @SuppressWarnings("rawtypes")
    public static InterceptPoint interceptPoint(Interceptor interceptor) {
        var a = interceptor.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        InterceptPoint ret;

        if (a == null) {
            // if class is not annotated, look for field interceptPoint
            ret = findInterceptPointField(interceptor.getClass(), interceptor);
        } else {
            ret = a.interceptPoint();
        }

        if (ret == InterceptPoint.ANY) {
            throw new IllegalArgumentException("intercept point ANY can only be used in dontIntercept attribute");
        } else {
            return ret;
        }
    }


    /**
     *
     * @param interceptor
     * @return the requiredinterceptor as defined by the @RegisterPlugin annotation
     */
    public static Boolean requiredinterceptor(Interceptor interceptor) {
        var a = interceptor.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        if (a == null) {
            return null;
        } else {
            return a.requiredinterceptor();
        }
    }

    /**
     * this is used to retrieve the interceptPoint of an Interceptor that is not annotated
     * with @RegisterPlugin
     *
     * @param clazz
     * @param o
     * @return
     */
    private static InterceptPoint findInterceptPointField(Class clazz, Object o) {
        try {
            var field = clazz.getDeclaredField("interceptPoint");
            field.setAccessible(true);

            var value = field.get(o);
            if (value instanceof InterceptPoint ip) {
                return ip;
            } else {
                return null;
            }
        } catch (NoSuchFieldException nfe) {
            if (clazz.getSuperclass() != null) {
                return findInterceptPointField(clazz.getSuperclass(), o);
            } else {
                return null;
            }
        } catch (Throwable t) {
            return null;
        }
    }

    public static InitPoint initPoint(Initializer initializer) {
        var a = initializer.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        if (a == null) {
            return null;
        } else {
            return a.initPoint();
        }
    }

    public static boolean requiresContent(Interceptor, ? extends Response> interceptor) {
        var a = interceptor.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        if (a == null) {
            return false;
        } else {
            return a.requiresContent();
        }
    }

    /**
     *
     * @param plugin
     * @return the plugin name
     */
    public static String name(Plugin plugin) {
        var a = plugin.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        if (a == null) {
            return findNameField(plugin.getClass(), plugin);
        } else {
            return a.name();
        }
    }

    /**
     * this is used to retrieve the name of a plugin that is not annotated
     * with @RegisterPlugin. Assumes the existance of the field 'name'.
     *
     * @param clazz
     * @param o
     * @return
     */
    private static String findNameField(Class clazz, Object o) {
        try {
            var field = clazz.getDeclaredField("name");
            field.setAccessible(true);

            var value = field.get(o);
            if (value instanceof String s) {
                return s;
            } else {
                return null;
            }
        } catch (NoSuchFieldException nfe) {
            if (clazz.getSuperclass() != null) {
                return findNameField(clazz.getSuperclass(), o);
            } else {
                return null;
            }
        } catch (Throwable t) {
            return null;
        }
    }

    /**
     *
     * @param service
     * @return the service default URI. If not explicitly set via defaulUri
     *         attribute, it is /[service-name]
     */
    @SuppressWarnings("rawtypes")
    public static String defaultURI(Service service) {
        var a = service.getClass().getDeclaredAnnotation(RegisterPlugin.class);

        return a == null ? null
                : a.defaultURI() == null || "".equals(a.defaultURI()) ? "/".concat(a.name()) : a.defaultURI();
    }

    /**
     *
     * @param service
     * @return uri match policy.
     */
    @SuppressWarnings("rawtypes")
    public static MATCH_POLICY uriMatchPolicy(Service service) {
        return service.getClass().getDeclaredAnnotation(RegisterPlugin.class).uriMatchPolicy();
    }

    /**
     *
     * @param 

* @param serviceClass * @return the service default URI. If not explicitly set via defaulUri * attribute, it is /[service-name] */ @SuppressWarnings("rawtypes") public static

String defaultURI(Class

serviceClass) { var a = serviceClass.getDeclaredAnnotation(RegisterPlugin.class); return a == null ? null : a.defaultURI() == null || "".equals(a.defaultURI()) ? "/".concat(a.name()) : a.defaultURI(); } /** * * @param

* @param conf the plugin configuration got from @InjectConfiguration * @param serviceClass the class of the service * @return the actual service uri set in cofiguration or the defaultURI */ @SuppressWarnings("rawtypes") public static

String actualUri(Map conf, Class

serviceClass) { if (conf != null && conf.get("uri") != null && conf.get("uri") instanceof String) { return (String) conf.get("uri"); } else { return PluginUtils.defaultURI(serviceClass); } } /** * * @param service * @return the intercept points of interceptors that must not be executed on * requests handled by service */ @SuppressWarnings("rawtypes") public static InterceptPoint[] dontIntercept(Service service) { if (service == null) { return null; } var a = service.getClass().getDeclaredAnnotation(RegisterPlugin.class); if (a == null) { return new InterceptPoint[0]; } else { return a.dontIntercept(); } } /** * * @param authorizer * @return the Authorizer type */ public static Authorizer.TYPE authorizerType(Authorizer authorizer) { if (authorizer == null) { return Authorizer.TYPE.ALLOWER; } var a = authorizer.getClass().getDeclaredAnnotation(RegisterPlugin.class); if (a == null) { return Authorizer.TYPE.ALLOWER; } else { return a.authorizerType(); } } public static boolean blocking(Service service) { if (service == null) { return true; } var a = service.getClass().getDeclaredAnnotation(RegisterPlugin.class); if (a == null) { return true; } else { return a.blocking(); } } /** * * @param registry * @param exchange * @return the service handling the exchange or null if the request is not * handled by a service */ public static Service handlingService(PluginsRegistry registry, HttpServerExchange exchange) { var pr = handlingServicePluginRecord(registry, exchange); return pr == null ? null : pr.getInstance(); } /** * * @param registry * @param exchange * @return the plugin record of the service handling the exchange or null if the request is not * handled by a service */ public static PluginRecord> handlingServicePluginRecord(PluginsRegistry registry, HttpServerExchange exchange) { var pi = Request.getPipelineInfo(exchange); if (pi != null && pi.getType() == SERVICE) { var srvName = pi.getName(); if (srvName != null) { var _s = registry.getServices().stream().filter(s -> srvName.equals(s.getName())).findAny(); if (_s.isPresent()) { return _s.get(); } } } return null; } /** * * @param registry * @param exchange * @return the intercept points of interceptors that must not be executed on the * exchange */ public static InterceptPoint[] dontIntercept(PluginsRegistry registry, HttpServerExchange exchange) { var hs = handlingService(registry, exchange); return hs == null ? new InterceptPoint[0] : dontIntercept(hs); } @SuppressWarnings("rawtypes") private static final LoadingCache RC = CacheFactory.createHashMapLoadingCache(plugin -> plugin.requestType()); @SuppressWarnings("rawtypes") private static final LoadingCache SC = CacheFactory.createHashMapLoadingCache(plugin -> plugin.responseType()); /** * Plugin.requestType() is heavy. This helper methods speeds up invocation using * a cache * * @param plugin * @return */ @SuppressWarnings("rawtypes") public static Type cachedRequestType(ExchangeTypeResolver plugin) { return RC.getLoading(plugin).get(); } /** * Plugin.responseType() is heavy. This helper methods speeds up invocation * using a cache * * @param plugin * @return */ @SuppressWarnings("rawtypes") public static Type cachedResponseType(ExchangeTypeResolver plugin) { return SC.getLoading(plugin).get(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy