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

io.gravitee.gateway.policy.impl.DefaultPolicyManager Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.
 */
package io.gravitee.gateway.policy.impl;

import io.gravitee.common.component.AbstractLifecycleComponent;
import io.gravitee.definition.model.Policy;
import io.gravitee.gateway.policy.*;
import io.gravitee.gateway.reactor.Reactable;
import io.gravitee.gateway.resource.ResourceLifecycleManager;
import io.gravitee.plugin.core.api.ConfigurablePluginManager;
import io.gravitee.plugin.core.api.PluginClassLoader;
import io.gravitee.plugin.policy.PolicyClassLoaderFactory;
import io.gravitee.plugin.policy.PolicyPlugin;
import io.gravitee.plugin.policy.internal.PolicyMethodResolver;
import io.gravitee.policy.api.PolicyConfiguration;
import io.gravitee.policy.api.PolicyContext;
import io.gravitee.policy.api.PolicyContextProviderAware;
import io.gravitee.resource.api.Resource;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;

/**
 * @author David BRASSELY (david.brassely at graviteesource.com)
 * @author GraviteeSource Team
 */
public class DefaultPolicyManager extends AbstractLifecycleComponent implements PolicyManager {

    private final Logger logger = LoggerFactory.getLogger(DefaultPolicyManager.class);

    @Autowired
    protected ApplicationContext applicationContext;

    protected PolicyFactory policyFactory;

    @Autowired
    protected PolicyConfigurationFactory policyConfigurationFactory;

    private final Map policies = new HashMap<>();

    public DefaultPolicyManager(PolicyFactory policyFactory) {
        this.policyFactory = policyFactory;
    }

    @Override
    protected void doStart() throws Exception {
        // Init required policies
        initialize();

        // Activate policy context
        policies
            .values()
            .stream()
            .filter(registeredPolicy -> registeredPolicy.context() != null)
            .forEach(
                registeredPolicy -> {
                    try {
                        logger.info(
                            "Activating context for {} [{}]",
                            registeredPolicy.id(),
                            registeredPolicy.context().getClass().getName()
                        );

                        registeredPolicy.context().onActivation();
                    } catch (Exception ex) {
                        logger.error("Unable to activate policy context", ex);
                    }
                }
            );
    }

    @Override
    protected void doStop() throws Exception {
        // Deactivate policy context
        policies
            .values()
            .stream()
            .filter(registeredPolicy -> registeredPolicy.context() != null)
            .forEach(
                registeredPolicy -> {
                    try {
                        logger.info(
                            "De-activating context for {} [{}]",
                            registeredPolicy.id(),
                            registeredPolicy.context().getClass().getName()
                        );
                        registeredPolicy.context().onDeactivation();
                    } catch (Exception ex) {
                        logger.error("Unable to deactivate policy context", ex);
                    }
                }
            );

        // Close policy classloaders
        policies
            .values()
            .forEach(
                policy -> {
                    ClassLoader policyClassLoader = policy.classloader();
                    if (policyClassLoader instanceof PluginClassLoader) {
                        try {
                            ((PluginClassLoader) policyClassLoader).close();
                        } catch (IOException e) {
                            logger.error("Unable to close policy classloader for policy {}", policy.id());
                        }
                    }
                }
            );

        // Be sure to remove all references to policies
        policies.clear();
    }

    protected Set dependencies() {
        Reactable reactable = applicationContext.getBean(Reactable.class);
        return reactable.dependencies(Policy.class);
    }

    private void initialize() {
        String[] beanNamesForType = getRootContext()
            .getBeanNamesForType(ResolvableType.forClassWithGenerics(ConfigurablePluginManager.class, PolicyPlugin.class));

        ConfigurablePluginManager ppm = (ConfigurablePluginManager) getRootContext()
            .getBean(beanNamesForType[0]);
        PolicyClassLoaderFactory pclf = applicationContext.getBean(PolicyClassLoaderFactory.class);
        ClassLoader globalClassLoader = getClassLoader();
        ResourceLifecycleManager rm = applicationContext.getBean(ResourceLifecycleManager.class);

        dependencies()
            .forEach(
                policy -> {
                    final PolicyPlugin policyPlugin = ppm.get(policy.getName());
                    if (policyPlugin == null) {
                        logger.error("Policy [{}] can not be found in policy registry", policy.getName());
                        throw new IllegalStateException("Policy [" + policy.getName() + "] can not be found in policy registry");
                    }

                    PluginClassLoader policyClassLoader;

                    // Load dependant resources to enhance policy classloader
                    Collection resources = rm.getResources();
                    if (!resources.isEmpty()) {
                        ClassLoader[] resourceClassLoaders = rm
                            .getResources()
                            .stream()
                            .map(
                                new Function() {
                                    @Override
                                    public ClassLoader apply(Resource resource) {
                                        return resource.getClass().getClassLoader();
                                    }
                                }
                            )
                            .toArray(ClassLoader[]::new);

                        DelegatingClassLoader parentClassLoader = new DelegatingClassLoader(globalClassLoader, resourceClassLoaders);
                        policyClassLoader = pclf.getOrCreateClassLoader(policyPlugin, parentClassLoader);
                    } else {
                        policyClassLoader = pclf.getOrCreateClassLoader(policyPlugin, globalClassLoader);
                    }

                    logger.debug("Loading policy {}", policy.getName());

                    PolicyMetadataBuilder builder = new PolicyMetadataBuilder();
                    builder.setId(policyPlugin.id());

                    try {
                        // Prepare metadata
                        Class policyClass = ClassUtils.forName(policyPlugin.policy().getName(), policyClassLoader);

                        builder
                            .setPolicy(policyClass)
                            .setClassLoader(policyClassLoader)
                            .setMethods(new PolicyMethodResolver().resolve(policyClass));

                        if (policyPlugin.configuration() != null) {
                            builder.setConfiguration(
                                (Class) ClassUtils.forName(
                                    policyPlugin.configuration().getName(),
                                    policyClassLoader
                                )
                            );
                        }

                        // Prepare context if defined
                        if (policyPlugin.context() != null) {
                            Class policyContextClass = (Class) ClassUtils.forName(
                                policyPlugin.context().getName(),
                                policyClassLoader
                            );
                            // Create policy context instance and initialize context provider (if used)
                            PolicyContext context = new PolicyContextFactory().create(policyContextClass);

                            if (context instanceof PolicyContextProviderAware) {
                                ((PolicyContextProviderAware) context).setPolicyContextProvider(
                                        new SpringPolicyContextProvider(applicationContext)
                                    );
                            }

                            builder.setContext(context);
                        }

                        policies.put(policy.getName(), builder.build());
                    } catch (Exception ex) {
                        logger.error("Unable to load policy metadata", ex);

                        if (policyClassLoader != null) {
                            try {
                                policyClassLoader.close();
                            } catch (IOException ioe) {
                                logger.error("Unable to close classloader for policy", ioe);
                            }
                        }
                    } catch (Error error) {
                        logger.error(
                            "Unable to load policy id[" +
                            policyPlugin.id() +
                            "]. This error mainly occurs when the policy is linked to a missing resource, for example a cache or an oauth2 resource. Please check your policy configuration!",
                            error
                        );

                        if (policyClassLoader != null) {
                            try {
                                policyClassLoader.close();
                            } catch (IOException ioe) {
                                logger.error("Unable to close classloader for policy", ioe);
                            }
                        }
                    }
                }
            );
    }

    public ApplicationContext getRootContext() {
        ApplicationContext rootContext = applicationContext;
        while (rootContext.getParent() != null) {
            rootContext = rootContext.getParent();
        }
        return rootContext;
    }

    protected ClassLoader getClassLoader() {
        return this.getClass().getClassLoader();
    }

    @Override
    public io.gravitee.gateway.policy.Policy create(StreamType streamType, String policy, String configuration) {
        PolicyMetadata metadata = policies.get(policy);

        if (metadata != null && metadata.accept(streamType)) {
            PolicyConfiguration policyConfiguration = policyConfigurationFactory.create(metadata.configuration(), configuration);

            return policyFactory.create(streamType, metadata, policyConfiguration);
        }

        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy