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

org.openl.rules.project.instantiation.WrapperAdjustingInstantiationStrategy Maven / Gradle / Ivy

There is a newer version: 5.27.9-jakarta
Show newest version
package org.openl.rules.project.instantiation;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.openl.CompiledOpenClass;
import org.openl.classloader.OpenLClassLoaderHelper;
import org.openl.classloader.SimpleBundleClassLoader;
import org.openl.dependency.IDependencyManager;
import org.openl.exception.OpenlNotCheckedException;
import org.openl.main.OpenLWrapper;
import org.openl.rules.project.model.Module;
import org.openl.rules.runtime.RulesEngineFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.*;
import java.net.URL;
import java.util.Map;

/**
 * Instantiation strategy for projects with Wrapper
 *
 * @author PUdalau
 */
public class WrapperAdjustingInstantiationStrategy extends SingleModuleInstantiationStrategy {

    private final Logger log = LoggerFactory.getLogger(WrapperAdjustingInstantiationStrategy.class);

    private OpenLWrapper wrapper;

    public WrapperAdjustingInstantiationStrategy(Module module, boolean executionMode,
                                                 IDependencyManager dependencyManager) {
        super(module, executionMode, dependencyManager);
    }

    public WrapperAdjustingInstantiationStrategy(Module module, boolean executionMode,
                                                 IDependencyManager dependencyManager, ClassLoader classLoader) {
        super(module, executionMode, dependencyManager, classLoader);
    }

    @SuppressWarnings("deprecation")
    @Override
    protected ClassLoader initClassLoader() {
        ClassLoader parent = getModule().getProject().getClassLoader(false);
        SimpleBundleClassLoader classLoader = new SimpleBundleClassLoader(parent);
        // Temporary decision.
        // It is done to ensure that wrapper class will be loaded with current
        // classloader.
        // Don`t need to load all urls from project, just wrapper class.
        URL[] urls = getModule().getProject().getClassPathUrls();
        OpenLClassLoaderHelper.extendClasspath(classLoader, urls);
        return classLoader;
    }

    @Override
    public void reset() {
        super.reset();
        try {
            if (isWrapperClassLoaded()) {
                reset(getServiceClass());
            }
            wrapper = null;
        } catch (Exception e) {
            log.error("Failed to reset wrapper '{}'.", getModule().getClassname(), e);
        }
    }

    protected boolean isWrapperClassLoaded() {
        return super.isServiceClassDefined();
    }

    @Override
    public void forcedReset() {
        super.forcedReset();
        super.setServiceClass(null);// it will cause reloading of service class
        // with
        // new classloader later
    }

    @Override
    public Class getServiceClass() throws ClassNotFoundException {
        if (!isWrapperClassLoaded()) {
            // Service class for current implementation will be wrapper class,
            // previously generated.

            Class wrapperClass = null;

            // Ensure that service class (e.g. wrapper class for current
            // strategy implementation)
            // will be loaded by strategy classLoader.
            //
            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(getClassLoader());
            try {
                wrapperClass = getWrapperClass();
                try {
                    // Before returning wrapper class, need to compile the
                    // project to ensure
                    // that all datatypes will be acessible from strategy
                    // classLoader.
                    compile(wrapperClass);
                } catch (Exception e) {
                    String errorMessage = String.format("Cannot compile %s module", getModule().getName());
                    throw new OpenlNotCheckedException(errorMessage, e);
                }
            } finally {
                Thread.currentThread().setContextClassLoader(oldClassLoader);
            }
            super.setServiceClass(wrapperClass);
        }
        return super.getServiceClass();
    }

    @Override
    public void setServiceClass(Class serviceClass) {
        log.warn("Service class changing is not allowed for static wrapper. Default static wrapper class will be used instead of '{}'", serviceClass.getName());
    }

    private Class getWrapperClass() throws ClassNotFoundException {
        return Class.forName(getModule().getClassname(), false, getClassLoader());
    }

    public Object wrapperNewInstance(Class wrapperClass) throws Exception {
        try {
            // NOTICE: Our bean datatype classes are loaded during compilation
            // and they may be used in wrapper
            // method signatures.
            // However, wrapper fields and constructors do not have those
            // classes references.
            // Due to Java lazy class loading it's safe to access fields and
            // constructor before Openl compilation.

            Constructor ctr = findConstructor(wrapperClass, new Class[]{boolean.class, boolean.class, Map.class,
                    IDependencyManager.class});

            if (ctr != null) {
                return ctr.newInstance(!isExecutionMode(), isExecutionMode(),
                        prepareExternalParameters(), getDependencyManager());
            }

            ctr = findConstructor(wrapperClass, new Class[]{boolean.class, boolean.class});

            if (ctr != null) {
                return ctr.newInstance(!isExecutionMode(), isExecutionMode());
            }

            ctr = wrapperClass.getConstructor(new Class[]{boolean.class});

            return ctr.newInstance(Boolean.TRUE);
        } catch (NoSuchMethodException e) {
            String errorMessage = String.format("Cannot find method in wrapper class %s. "
                            + "You are using older version of OpenL Wrapper, please run Generate ... Wrapper",
                    wrapperClass.getName());
            log.error(errorMessage, e);
            throw new OpenlNotCheckedException(errorMessage, e);
        }
    }

    @Override
    public CompiledOpenClass compile() throws RulesInstantiationException {
        try {
            return compile(getServiceClass());
        } catch (ClassNotFoundException e) {
            String errorMessage = String.format("Cannot find service class for %s", getModule().getClassname());
            log.error(errorMessage, e);
            throw new RulesInstantiationException(errorMessage, e);
        } catch (UnsupportedClassVersionError e) {
            String errorMessage = String.format(
                    "Can't load a class compiled using newer version of JDK than current JRE (%s)",
                    System.getProperty("java.version"));
            log.error(errorMessage, e);
            throw new RulesInstantiationException(errorMessage, e);
        }
    }

    @Override
    public OpenLWrapper instantiate(Class wrapperClass) throws RulesInstantiationException {

        // Ensure that instantiation will be done in strategy classloader.
        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(getClassLoader());

        try {
            preInitWrapper(wrapperClass);
            if (wrapper == null) {
                wrapper = (OpenLWrapper) wrapperNewInstance(wrapperClass);
            }
            return wrapper;
        } catch (Exception e) {
            String errorMessage = String.format("Failed to instantiate wrapper %s", wrapperClass.getName());
            log.error(errorMessage, e);
            throw new RulesInstantiationException(errorMessage, e);
        } finally {
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }
    }

    private void reset(Class wrapperClass) throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        // When calling getMethod() all declared methods from the class are
        // loading with its parameters classes and
        // return classes.
        Method m = wrapperClass.getMethod("reset", new Class[]{});
        m.invoke(null); // we reset to reload wrapper due
        // to its static implementation
    }

    /**
     * Compiles the wrapper class.
     *
     * @return {@link CompiledOpenClass}
     * @throws RulesInstantiationException
     */
    private CompiledOpenClass compile(Class wrapperClass) throws RulesInstantiationException {
        OpenLWrapper wrapper = instantiate(wrapperClass);

        return wrapper.getCompiledOpenClass();
    }

    private Constructor findConstructor(Class clazz, Class[] parameterTypes) {
        return ConstructorUtils.getMatchingAccessibleConstructor(clazz, parameterTypes);
    }

    private void preInitWrapper(Class clazz) throws Exception {
        String projectFolder = getModule().getProject().getProjectFolder().getAbsolutePath();
        Field userHomeField = clazz.getField("__userHome");
        if (Modifier.isStatic(userHomeField.getModifiers())) {
            userHomeField.set(null, projectFolder);
        } else {
            String errorMessage = String.format("Field %s is not static in %s", userHomeField.getName(), userHomeField
                    .getDeclaringClass().getName());
            log.error(errorMessage);
            throw new OpenlNotCheckedException(errorMessage);
        }
        try {
            Field field = clazz.getField("__src");
            String sourcePath = (String) field.get(null);
            if (!new File(sourcePath).isAbsolute()) {
                field.set(null, projectFolder + '/' + sourcePath);
            }
        } catch (Exception e) {
            String errorMessage = "Failed to set up __src";
            log.error(errorMessage, e);
            throw new OpenlNotCheckedException(errorMessage, e);
        }
    }

    @Override
    public boolean isServiceClassDefined() {
        return true;
    }

	@Override
	protected RulesEngineFactory getEngineFactory()
			throws RulesInstantiationException {
		throw new UnsupportedOperationException();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy