net.ymate.platform.plugin.impl.DefaultPluginFactory.java Source code

Java tutorial

Introduction

Here is the source code for net.ymate.platform.plugin.impl.DefaultPluginFactory.java

Source

/*
 * Copyright 2007-2016 the original author or authors.
 *
 * 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 net.ymate.platform.plugin.impl;

import net.ymate.platform.core.YMP;
import net.ymate.platform.core.beans.*;
import net.ymate.platform.core.beans.annotation.Bean;
import net.ymate.platform.core.beans.annotation.Proxy;
import net.ymate.platform.core.beans.impl.DefaultBeanFactory;
import net.ymate.platform.core.beans.impl.DefaultBeanLoader;
import net.ymate.platform.core.handle.ProxyHandler;
import net.ymate.platform.core.util.ClassUtils;
import net.ymate.platform.core.util.RuntimeUtils;
import net.ymate.platform.plugin.*;
import net.ymate.platform.plugin.annotation.Handler;
import net.ymate.platform.plugin.annotation.Plugin;
import net.ymate.platform.plugin.handle.BeanHandler;
import net.ymate.platform.plugin.handle.PluginHandler;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ??
 *
 * @author  (suninformation@163.com) on 2012-12-2 ?3:22:17
 * @version 1.0
 */
public class DefaultPluginFactory implements IPluginFactory {

    private static final Log _LOG = LogFactory.getLog(DefaultPluginFactory.class);

    private IBeanFactory __innerBeanFactory;

    private IBeanFactory __outerBeanFactory;

    private IPluginConfig __config;

    private IPluginEventListener __event;

    private PluginClassLoader __pluginClassLoader;

    /**
     * PluginID -> PluginMeta
     */
    private Map<String, PluginMeta> __pluginMetaWithId;

    /**
     * PluginClass -&gt; PluginMeta
     */
    private Map<Class<? extends IPlugin>, PluginMeta> __pluginMetaWithClass;

    private YMP __owner;

    private boolean __inited;

    public DefaultPluginFactory() {
        this(null);
    }

    public DefaultPluginFactory(YMP owner) {
        __owner = owner;
        //
        __pluginMetaWithId = new ConcurrentHashMap<String, PluginMeta>();
        __pluginMetaWithClass = new ConcurrentHashMap<Class<? extends IPlugin>, PluginMeta>();
        //
        __innerBeanFactory = __doBuildBeanFactory(this, true);
        __outerBeanFactory = __doBuildBeanFactory(this, false);
        __innerBeanFactory.registerHandler(Plugin.class, new PluginHandler(this));
        __outerBeanFactory.registerHandler(Plugin.class, new PluginHandler(this));
    }

    @SuppressWarnings("unchecked")
    private List<Class<? extends IBeanHandler>> __doLoadBeanHandles() throws Exception {
        List<Class<? extends IBeanHandler>> _returnValues = new ArrayList<Class<? extends IBeanHandler>>();
        IBeanLoader _loader = new DefaultBeanLoader();
        //
        IBeanFilter _beanFilter = new IBeanFilter() {
            public boolean filter(Class<?> targetClass) {
                return !(targetClass.isInterface() || targetClass.isAnnotation() || targetClass.isEnum())
                        && (targetClass.isAnnotationPresent(Handler.class)
                                && ClassUtils.isInterfaceOf(targetClass, IBeanHandler.class));
            }
        };
        //
        for (String _package : __config.getAutoscanPackages()) {
            for (Class<?> _targetClass : _loader.load(_package, _beanFilter)) {
                _returnValues.add((Class<? extends IBeanHandler>) _targetClass);
            }
        }
        return _returnValues;
    }

    public void init(IPluginConfig pluginConfig) throws Exception {
        if (!__inited) {
            this.__config = pluginConfig;
            //
            if (__owner != null) {
                __owner.bindBeanFactory(__innerBeanFactory);
                //
                __outerBeanFactory.registerHandler(Bean.class, new BeanHandler(this));
                __outerBeanFactory.registerHandler(Proxy.class, new ProxyHandler(__owner));
                //
                for (Class<? extends IBeanHandler> _targetClass : __doLoadBeanHandles()) {
                    __outerBeanFactory.registerHandler(_targetClass.getAnnotation(Handler.class).value(),
                            _targetClass.getConstructor(YMP.class).newInstance(__owner));
                }
            }
            //
            __event = __config.getPluginEventListener();
            if (__event == null) {
                __event = new DefaultPluginEventListener();
            }
            //
            __pluginClassLoader = __buildPluginClassLoader();
            __outerBeanFactory.setLoader(
                    new DefaultBeanLoader(__owner != null ? __owner.getConfig().getExcudedFiles() : null) {
                        @Override
                        public ClassLoader getClassLoader() {
                            return __pluginClassLoader;
                        }
                    });
            __outerBeanFactory.setParent(__innerBeanFactory);
            //
            for (String _package : __config.getAutoscanPackages()) {
                __innerBeanFactory.registerPackage(_package);
                __outerBeanFactory.registerPackage(_package);
            }
            if (__config.isIncludedClassPath()) {
                __innerBeanFactory.init();
            }
            __outerBeanFactory.init();
            __outerBeanFactory.initIoC();
            __inited = true;
            //
            for (Map.Entry<Class<? extends IPlugin>, PluginMeta> _meta : __pluginMetaWithClass.entrySet()) {
                IPlugin _plugin = __outerBeanFactory.getBean(_meta.getKey());
                _plugin.init(new DefaultPluginContext(this, _meta.getValue()));
                __event.onInited(_plugin.getPluginContext(), _plugin);
                //
                if (__config.isAutomatic() && _meta.getValue().isAutomatic()) {
                    _plugin.startup();
                    __event.onStarted(_plugin.getPluginContext(), _plugin);
                }
            }
        }
    }

    private IBeanFactory __doBuildBeanFactory(final IPluginFactory factory, final boolean inner) {
        return new DefaultBeanFactory() {
            @Override
            protected void __addClass(BeanMeta beanMeta) {
                PluginMeta _meta = (PluginMeta) beanMeta.getBeanObject();
                //
                if (inner && !factory.getPluginConfig().isIncludedClassPath()) {
                    if (StringUtils.isNotBlank(_meta.getPath())) {
                        return;
                    }
                }
                //
                IPluginContext _context = new DefaultPluginContext(factory, _meta);
                IPlugin _plugin = ClassUtils.impl(beanMeta.getBeanClass(), IPlugin.class);
                if (_plugin != null) {
                    // ?IPluginExtend???
                    if (_meta.getExtendObject() == null
                            && ClassUtils.isInterfaceOf(beanMeta.getBeanClass(), IPluginExtend.class)) {
                        IPluginExtend _extend = (IPluginExtend) _plugin;
                        _meta.setExtendObject(_extend.getExtendObject(_context));
                    }
                    //
                    boolean _emptyPath = StringUtils.isBlank(_meta.getPath());
                    if ((inner && _emptyPath) || (!inner && !_emptyPath)) {
                        super.__addClass(BeanMeta.create(_plugin, beanMeta.getBeanClass()));
                        //
                        __pluginMetaWithId.put(_meta.getId(), _meta);
                        __pluginMetaWithClass.put(_meta.getInitClass(), _meta);
                    }
                }
            }
        };
    }

    private synchronized PluginClassLoader __buildPluginClassLoader() throws Exception {
        if (__pluginClassLoader == null) {
            if (__config.getPluginHome() != null && __config.getPluginHome().exists()
                    && __config.getPluginHome().isDirectory()) {
                List<URL> _libs = new ArrayList<URL>();
                // ????
                File _commonFile = new File(__config.getPluginHome(), ".plugin");
                if (_commonFile.exists() && _commonFile.isDirectory()) {
                    try {
                        // JAR
                        File _tempFile = new File(_commonFile, "lib");
                        if (_tempFile.exists() && _tempFile.isDirectory()) {
                            File[] _libFiles = _tempFile.listFiles();
                            for (File _libFile : _libFiles != null ? _libFiles : new File[0]) {
                                if (_libFile.getPath().endsWith("jar")) {
                                    _libs.add(_libFile.toURI().toURL());
                                }
                            }
                        }
                        // 
                        _tempFile = new File(_commonFile, "classes");
                        if (_tempFile.exists() && _tempFile.isDirectory()) {
                            _libs.add(_tempFile.toURI().toURL());
                        }
                    } catch (MalformedURLException e) {
                        _LOG.warn("", e);
                    }
                }
                // ????(????'.')
                File[] _pluginDirs = __config.getPluginHome().listFiles();
                if (_pluginDirs != null)
                    for (File _pluginDir : _pluginDirs) {
                        if (_pluginDir.isDirectory() && _pluginDir.getName().charAt(0) != '.') {
                            // JAR
                            File _pluginLibDir = new File(_pluginDir, "lib");
                            if (_pluginLibDir.exists() && _pluginLibDir.isDirectory()) {
                                File[] _libFiles = _pluginLibDir.listFiles();
                                if (_libFiles != null)
                                    for (File _libFile : _libFiles) {
                                        if (_libFile.isFile() && _libFile.getAbsolutePath().endsWith("jar")) {
                                            _libs.add(_libFile.toURI().toURL());
                                        }
                                    }
                            }
                            // 
                            _pluginLibDir = new File(_pluginDir, "classes");
                            if (_pluginLibDir.exists() && _pluginLibDir.isDirectory()) {
                                _libs.add(_pluginLibDir.toURI().toURL());
                            }
                        }
                    }
                //
                __pluginClassLoader = new PluginClassLoader(__config.getPluginHome().getPath(),
                        _libs.toArray(new URL[_libs.size()]), this.getClass().getClassLoader());
            } else {
                throw new IllegalArgumentException("The pluginHome parameter is invalid");
            }
        }
        return __pluginClassLoader;
    }

    public boolean isInited() {
        return __inited;
    }

    public void destroy() throws Exception {
        if (__inited) {
            __inited = false;
            //
            for (Map.Entry<Class<? extends IPlugin>, PluginMeta> _meta : __pluginMetaWithClass.entrySet()) {
                IPlugin _plugin = __outerBeanFactory.getBean(_meta.getKey());
                if (_plugin != null) {
                    _plugin.shutdown();
                    __event.onShutdown(_plugin.getPluginContext(), _plugin);
                    //
                    __event.onDestroy(_plugin.getPluginContext(), _plugin);
                    _plugin.destroy();
                }
            }
            //
            __config = null;
            __pluginClassLoader = null;
            //
            __pluginMetaWithId = null;
            __pluginMetaWithClass = null;
            //
            __outerBeanFactory.destroy();
            __outerBeanFactory = null;
            //
            __innerBeanFactory.destroy();
            __innerBeanFactory = null;
        }
    }

    public void addExcludedInterfaceClass(Class<?> interfaceClass) {
        __innerBeanFactory.registerExcludedClass(interfaceClass);
        __outerBeanFactory.registerExcludedClass(interfaceClass);
    }

    public YMP getOwner() {
        return __owner;
    }

    public IPluginConfig getPluginConfig() {
        return __config;
    }

    private void __pluginStatusChecker(IPlugin plugin) {
        if (plugin.isInited() && !plugin.isStarted()) {
            try {
                plugin.startup();
                __event.onStarted(plugin.getPluginContext(), plugin);
            } catch (Exception e) {
                throw new RuntimeException(RuntimeUtils.unwrapThrow(e));
            }
        }
    }

    public IPlugin getPlugin(String id) {
        IPlugin _plugin = null;
        if (__pluginMetaWithId.containsKey(id)) {
            _plugin = __outerBeanFactory.getBean(__pluginMetaWithId.get(id).getInitClass());
            __pluginStatusChecker(_plugin);
        }
        return _plugin;
    }

    public <T> T getPlugin(Class<T> clazz) {
        T _target = __outerBeanFactory.getBean(clazz);
        __pluginStatusChecker((IPlugin) _target);
        return _target;
    }

    public PluginMeta getPluginMeta(String id) {
        return __pluginMetaWithId.get(id);
    }

    public PluginMeta getPluginMeta(Class<? extends IPlugin> clazz) {
        return __pluginMetaWithClass.get(clazz);
    }
}