
com.jianggujin.modulelink.impl.JAbstractModuleManager Maven / Gradle / Ivy
/**
* Copyright 2018 jianggujin (www.jianggujin.com).
*
* 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 com.jianggujin.modulelink.impl;
import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.jianggujin.modulelink.JModule;
import com.jianggujin.modulelink.JModuleConfig;
import com.jianggujin.modulelink.JModuleLinkException;
import com.jianggujin.modulelink.JModuleManager;
import com.jianggujin.modulelink.JModuleNotFoundException;
import com.jianggujin.modulelink.util.JAssert;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;
import com.jianggujin.modulelink.util.JModuleClassLoader;
import com.jianggujin.modulelink.util.JModuleUtils;
/**
* 模块管理器抽象实现
*
* @author jianggujin
*
*/
public abstract class JAbstractModuleManager implements JModuleManager {
private static final JLog logger = JLogFactory.getLog(JAbstractModuleManager.class);
private final ConcurrentHashMap parallelLockMap;
public JAbstractModuleManager() {
parallelLockMap = new ConcurrentHashMap();
}
/**
* 已注册的所有模块,key:moduleName
*/
private final Map modules = new ConcurrentHashMap();
@Override
public JModule load(JModuleConfig moduleConfig) {
JAssert.checkNotNull(moduleConfig, "moduleConfig must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading module: " + moduleConfig);
}
String moduleName = moduleConfig.getName(), version = moduleConfig.getVersion();
JModule module = null;
synchronized (getLock(moduleName)) {
JRuntimeModule runtimeModule = this.modules.get(moduleName);
JAssert.checkState(runtimeModule == null || !runtimeModule.hasVersion(version), "module name already exists");
if (runtimeModule == null) {
runtimeModule = new JRuntimeModule(moduleName);
this.modules.put(moduleName, runtimeModule);
}
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
// 获取模块的ClassLoader
ClassLoader moduleClassLoader = new JModuleClassLoader(moduleConfig.getModuleUrls(), getParentClassLoader(),
moduleConfig.getOverridePackages());
try {
// 把当前线程的ClassLoader切换成模块的
Thread.currentThread().setContextClassLoader(moduleClassLoader);
module = load(moduleConfig, moduleClassLoader);
if (module == null) {
throw new NullPointerException("load module is null.");
}
runtimeModule.add(module);
} catch (Throwable e) {
loadModuleError(moduleClassLoader);
throw new JModuleLinkException("load module error.", e);
} finally {
// 还原当前线程的ClassLoader
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
}
if (logger.isInfoEnabled()) {
logger.info("loading module complete:" + moduleConfig);
}
return module;
}
/**
* 获得父级ClassLoader
*
* @return
*/
protected ClassLoader getParentClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
/**
* 加载模块
*
* @param moduleConfig
* @param moduleClassLoader
* @return
* @throws Exception
*/
protected abstract JModule load(JModuleConfig moduleConfig, ClassLoader moduleClassLoader) throws Exception;
/**
* 加载模块失败,此处可以做一些清理的事情
*
* @param moduleClassLoader
*/
protected void loadModuleError(ClassLoader moduleClassLoader) {
Introspector.flushCaches();
// 从已经使用给定类加载器加载的缓存中移除所有资源包
ResourceBundle.clearCache(moduleClassLoader);
}
@Override
public void unload(String name) {
JAssert.checkNotNull(name, "module name must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.remove(name);
if (runtimeModule == null) {
throw new JModuleNotFoundException("could not found module with name:" + name);
}
Collection list = null;
if ((list = runtimeModule.clear()) != null) {
for (JModule module : list) {
JModuleUtils.destroyQuietly(module);
}
}
}
}
@Override
public void unload(String name, String version) {
JAssert.checkNotNull(name, "module name must not be null");
JAssert.checkNotNull(version, "module version must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.get(name);
if (runtimeModule == null) {
throw new JModuleNotFoundException("could not found module with name:" + name);
}
JModule module = runtimeModule.remove(version);
if (module == null) {
throw new JModuleNotFoundException("could not found module with name:" + name + " and version:" + version);
}
JModuleUtils.destroyQuietly(module);
// 移除空数据
if (runtimeModule.count() == 0) {
this.modules.remove(name);
}
}
}
@Override
public JModule find(String name) {
JAssert.checkNotNull(name, "module name must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.get(name);
if (runtimeModule == null)
throw new JModuleNotFoundException("could not found module with name:" + name);
JModule module = runtimeModule.getDefaultModule();
if (module == null)
throw new JModuleNotFoundException("could not found module with name:" + name);
return module;
}
}
@Override
public JModule find(String name, String version) {
JAssert.checkNotNull(name, "module name must not be null");
JAssert.checkNotNull(version, "module version must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.get(name);
if (runtimeModule == null)
throw new JModuleNotFoundException("could not found module with name:" + name);
JModule module = runtimeModule.findModule(version);
if (module == null)
throw new JModuleNotFoundException("could not found module with name:" + name + " and version:" + version);
return module;
}
}
@Override
public void activeVersion(String name, String version) {
JAssert.checkNotNull(name, "module name must not be null");
JAssert.checkNotNull(version, "module version must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.get(name);
if (runtimeModule == null)
throw new JModuleNotFoundException("could not found module with name:" + name);
runtimeModule.setDefaultVersion(version);
}
}
@Override
public String getActiveVersion(String name) {
JAssert.checkNotNull(name, "module name must not be null");
synchronized (getLock(name)) {
JRuntimeModule runtimeModule = this.modules.get(name);
if (runtimeModule == null)
throw new JModuleNotFoundException("could not found module with name:" + name);
return runtimeModule.getDefaultVersion();
}
}
@Override
public boolean has(String name) {
if (name == null)
return false;
synchronized (getLock(name)) {
return this.modules.containsKey(name);
}
}
@Override
public Set getModuleNames() {
return Collections.unmodifiableSet(this.modules.keySet());
}
@Override
public List getModules() {
List modules = new ArrayList();
for (JRuntimeModule runtimeModule : this.modules.values()) {
modules.addAll(runtimeModule.list());
}
return Collections.unmodifiableList(modules);
}
/**
* 获得密钥加载锁
*
* @param uid
* @return
*/
protected Object getLock(String uid) {
Object lock = this;
if (parallelLockMap != null) {
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(uid, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy