帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

414 lines
17 KiB

package com.fanruan.boot.env;
import com.fanruan.boot.FSProperties;
import com.fanruan.boot.KVProperties;
import com.fanruan.boot.LoggerProperties;
import com.fanruan.boot.SchedulerCoreComponent;
import com.fanruan.carina.Carina;
import com.fanruan.carina.annotions.FineComponent;
import com.fanruan.carina.annotions.JPAEntityScan;
import com.fanruan.carina.annotions.Start;
import com.fanruan.carina.annotions.Stop;
import com.fanruan.carina.annotions.Supplemental;
import com.fanruan.config.ConfigProviderFactory;
import com.fanruan.config.realm.ConfigRealm;
import com.fanruan.dao.context.DBContextProvider;
import com.fanruan.dao.context.DBContextStarter;
import com.fanruan.dao.property.DBPropertyProvider;
import com.fanruan.dao.shell.DBContextShell;
import com.fanruan.dao.shell.DBPropertyShell;
import com.fanruan.fs.DesignFileRepository;
import com.fanruan.fs.FileServer;
import com.fanruan.fs.RepositoryFactory;
import com.fanruan.fs.repository.local.LocalFileRepository;
import com.fanruan.kv.CarinaKV;
import com.fanruan.kv.factory.KVStoreFactory;
import com.fanruan.kv.manager.CarinaKVManager;
import com.fanruan.kv.store.KVStore;
import com.fanruan.kv.store.KVStoreHolder;
import com.fanruan.workplace.http.RepositoryManager;
import com.fr.cbb.dialect.security.InsecurityElementFactory;
import com.fr.cluster.ClusterBridge;
import com.fr.cluster.lock.ClusterLock;
import com.fr.config.BaseDBEnv;
import com.fr.config.ConfigEvent;
import com.fr.config.Configuration;
import com.fr.config.FinalPreferenceConfig;
import com.fr.config.dao.DaoContext;
import com.fr.config.dao.impl.BatchSubmitClassHelperDao;
import com.fr.config.dao.impl.BatchSubmitEntityDao;
import com.fr.config.dao.impl.BatchSubmitXmlEntityDao;
import com.fr.config.dao.impl.hibernate.HibernateClassHelperDao;
import com.fr.config.dao.impl.hibernate.HibernateEntityDao;
import com.fr.config.dao.impl.hibernate.HibernateXmlEnityDao;
import com.fr.config.dao.impl.remote.RemoteClassHelperDao;
import com.fr.config.dao.impl.remote.RemoteEntityDao;
import com.fr.config.dao.impl.remote.RemoteXmlEntityDao;
import com.fr.config.holder.ConfigChangeListener;
import com.fr.config.holder.ValidateConfigManger;
import com.fr.config.impl.ConfConfigProviderImpl;
import com.fr.config.impl.ConfigInsecurityElementProviderImpl;
import com.fr.decision.service.context.ServiceContext;
import com.fr.design.backup.EnvBackupHelper;
import com.fr.env.detect.EnvDetectorCenter;
import com.fr.event.EventDispatcher;
import com.fr.general.FRLogger;
import com.fr.general.log.Log4jConfig;
import com.fr.general.log.Log4jUtils;
import com.fr.intelli.metrics.Compute;
import com.fr.intelli.metrics.DBMonitorInterceptor;
import com.fr.intelli.metrics.MonitorInterceptor;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.FocusInterceptor;
import com.fr.intelli.record.PerformancePoint;
import com.fr.intelli.record.PerformancePointInterceptor;
import com.fr.io.base.ResourcePaths;
import com.fr.io.repository.ResourceRepository;
import com.fr.io.repository.ResourceRepositoryWrapper;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.record.analyzer.AnalyzerConfiguration;
import com.fr.record.analyzer.AnalyzerMutableGroup;
import com.fr.record.analyzer.DBMetrics;
import com.fr.scheduler.QuartzContext;
import com.fr.scheduler.SchedulerEvent;
import com.fr.scheduler.tenant.ScheduleThreadCurrentTenantProvider;
import com.fr.security.encryption.EncryptionInitialization;
import com.fr.security.encryption.SystemEncryptionManager;
import com.fr.security.encryption.core.EncryptionScaffold;
import com.fr.security.encryption.provider.SecuritySeedProvider;
import com.fr.security.encryption.storage.keys.LoadSeedSecurityKey;
import com.fr.stable.StringUtils;
import com.fr.stable.db.DBContext;
import com.fr.stable.db.properties.FineMicroServicesDBProperties;
import com.fr.stable.db.session.DBSession;
import com.fr.stable.project.ProjectConstants;
import com.fr.tenant.context.TenantContext;
import com.fr.tenant.context.provider.CurrentTenantKey;
import com.fr.third.apache.logging.log4j.core.config.Configurator;
import com.fr.third.net.bytebuddy.implementation.MethodDelegation;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.org.hibernate.jdbc.AbstractWork;
import com.fr.tolerance.FaultTolerance;
import com.fr.tolerance.FaultToleranceInterceptor;
import com.fr.transaction.Configurations;
import com.fr.transaction.FineConfigurationHelper;
import com.fr.transaction.HibernateTransactor;
import com.fr.transaction.RemoteTransactor;
import com.fr.transaction.TransactorFactory;
import com.fr.workspace.WorkContext;
import java.net.URI;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* 设计器env模块,环境切换的底层模块
*
* @author Destiny.Lin
* @since 11.0
* Created on 2024/6/7
*/
@FineComponent(name = "design_env_prepare")
@JPAEntityScan({"com.fr.config.entity",
"com.fr.decision.authority.entity",
"com.fanruan.user.oa.basic.db.entity",
"com.fr.decision.system.entity",
"com.fr.decision.workflow.bean",
"com.fr.report.entity",
"com.fr.report.write.entity"
})
public class DesignEnvComponent {
/**
* prepare
*/
@Supplemental
public void prepare() {
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.isAnnotatedWith(Focus.class))
.intercept(MethodDelegation.to(FocusInterceptor.class))));
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.isAnnotatedWith(Compute.class))
.intercept(MethodDelegation.to(MonitorInterceptor.class))));
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.isAnnotatedWith(DBMetrics.class))
.intercept(MethodDelegation.to(DBMonitorInterceptor.class))));
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.isAnnotatedWith(PerformancePoint.class))
.intercept(MethodDelegation.to(PerformancePointInterceptor.class))));
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.isAnnotatedWith(FaultTolerance.class))
.intercept(MethodDelegation.to(FaultToleranceInterceptor.class))));
Carina.getApplicationContext().group(CurrentTenantKey.class).add(ScheduleThreadCurrentTenantProvider.INSTANCE);
}
@Start
public void start() throws Exception {
// 1.环境准备
startEnvPrepare();
// 2.core准备
startCorePrepare();
// 3.dao启动
startDao();
// 4.config启动
startConfConfig();
// 5.fileServer启动
startFileServer();
// 6.logger启动
startLogger();
// 7.kv
startKv();
// 8.scheduler
startScheduler();
}
private void startScheduler() {
if (WorkContext.getCurrent().isLocal()) {
TenantContext.doIsolatedWork(() -> {
ClusterLock lock = ClusterBridge.getLockFactory().get(SchedulerCoreComponent.class);
// 多节点同时启动quartz模块可能会产生脏数据,导致报错,使用集群锁控制一下
DBSession dbSession = null;
try {
lock.lock();
final DBContextProvider context = BaseDBEnv.getDBContext();
if (context == null) {
throw new IllegalArgumentException("ConfigDBActivator must start before SchedulerActivator");
}
dbSession = context.openSession();
dbSession.doWork(new AbstractWork() {
@Override
public void execute(Connection connection) throws SQLException {
//quartz需要的数据库方言
Properties properties = context.getDBProperties();
QuartzContext.getInstance().initScheduler(properties);
}
});
EventDispatcher.fire(SchedulerEvent.START);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} finally {
if (dbSession != null) {
dbSession.closeSession();
}
lock.unlock();
}
}, "default");
}
}
@Stop
public void stop() {
stopScheduler();
stopLogger();
stopFileServer();
stopConfConfig();
stopDao();
stopCorePrepare();
stopEnvPrepare();
}
private void stopScheduler() {
EventDispatcher.fire(SchedulerEvent.STOP);
QuartzContext.getInstance().destroy();
}
/**
* -------------------private-------------------
*/
/**
* ----------kv---------
*/
private void startKv() {
// KVProperties没有的话默认走内存
KVStore kvStore = KVStoreFactory.createFineKVStore(Carina.properties(KVProperties.class).getType());
KVStoreHolder.getInstance().setStore(kvStore);
CarinaKV.switchTo(new CarinaKVManager());
}
/**
* ----------- logger --------
*/
private void startLogger() {
String realPath = Carina.properties(LoggerProperties.class).getXml();
URI uri = Log4jUtils.buildUserConfigURI(realPath);
FRLogger.getLogger().config(uri);
// 日志配置更新的监听在FRLogger里面,fbp去掉了但是设计器本地还是需要这个监听的,初始化的时候监听一下
listenConfig();
}
private void listenConfig() {
ValidateConfigManger.getInstance().registerListener(new ConfigChangeListener() {
@Override
public boolean accept(Class<? extends Configuration> configClass) {
return configClass.equals(Log4jConfig.class);
}
@Override
public void change() {
// The root logger is the topmost logger with a name of "" (the empty string).
Configurator.setAllLevels("", Log4jConfig.getInstance().getRootLevel());
}
});
}
private void stopLogger() {
FRLogger.getLogger().stop();
}
/**
* ----------- file-server --------
*/
private void startFileServer() throws Exception {
if (WorkContext.getCurrent().isLocal()) {
// 设计器远程下不需要文件系统,走PublicRepo的接口,本地下走基础的磁盘读写
LocalFileRepository.getSingleton().setWorkRoot(ServiceContext.getWebInfPath());
ResourceRepository realRepo = RepositoryFactory.getRepo();
FSProperties fsProperties = Carina.properties(FSProperties.class);
FileServer.init(
new ResourceRepositoryWrapper(LocalFileRepository.getSingleton(), StringUtils.EMPTY),
new ResourceRepositoryWrapper(realRepo, StringUtils.EMPTY),
new ResourceRepositoryWrapper(realRepo, StringUtils.EMPTY),
new ResourceRepositoryWrapper(realRepo.generateTenantsSharedRepo(fsProperties.getTenantsSharedNamespace()), StringUtils.EMPTY));
ResourceIOUtils.setUnderlying(FileServer.local());
ResourceIOUtils.setIsolationMode(false);
ResourcePaths.register(ProjectConstants.ASSETS_NAME, true);
ResourcePaths.register(ProjectConstants.SCHEDULE_NAME, false);
} else {
DesignFileRepository repository = new DesignFileRepository();
FSProperties fsProperties = Carina.properties(FSProperties.class);
FileServer.init(repository, repository, repository, repository.generateTenantsSharedRepo(fsProperties.getTenantsSharedNamespace()));
}
}
private void stopFileServer() {
ResourceIOUtils.setUnderlying(FileServer.local());
ResourceIOUtils.setIsolationMode(true);
}
/**
* -----------dao---------
*/
private void startDao() {
if (WorkContext.getCurrent().isLocal()) {
// 类似com.fr.config.activator.BaseDBActivator.start里的逻辑
DBPropertyProvider dbPropertyProvider = FineMicroServicesDBProperties.getInstance().from(Carina.getApplicationContext().getCarinaApplicationProperties());
DBContextProvider dbContextProvider = new DBContextStarter(dbPropertyProvider).start();
ServiceContext.singleton(DBPropertyShell.class).set(dbPropertyProvider);
ServiceContext.singleton(DBContextShell.class).set(dbContextProvider);
// 这里等另外的模块DBPropertyComponent启动,并且注入后这里的api实例才能安排
FineLoggerFactory.getLogger().info("[StateServiceCommon] dao service common started.");
}
}
private void stopDao() {
FineMicroServicesDBProperties.getInstance().clear();
}
/**
* ---------- confconfig -------
*/
private void startConfConfig() {
if (EnvBackupHelper.getInstance().isSwtiching()) {
// 如果是切换环境触发的start,说明此时读的是新环境的配置
EnvBackupHelper.getInstance().do4Switch4Config();
}
BaseDBEnv.setDBContext((DBContext) Carina.getApplicationContext().singleton(DBContextShell.class).get());
if (!WorkContext.getCurrent().isLocal()) {
TransactorFactory.setTransactor(new RemoteTransactor());
//远程
DaoContext.setXmlEntityDao(new RemoteXmlEntityDao());
DaoContext.setClassHelperDao(new RemoteClassHelperDao());
DaoContext.setEntityDao(new RemoteEntityDao());
} else {
//本地
TransactorFactory.setTransactor(new HibernateTransactor());
DaoContext.setClassHelperDao(new BatchSubmitClassHelperDao(new HibernateClassHelperDao()));
DaoContext.setEntityDao(new BatchSubmitEntityDao(new HibernateEntityDao()));
DaoContext.setXmlEntityDao(new BatchSubmitXmlEntityDao(new HibernateXmlEnityDao()));
}
ConfConfigProviderImpl confConfigProvider = new ConfConfigProviderImpl();
ConfigProviderFactory.getInstance().registerProvider(ConfigRealm.SERVICE, confConfigProvider);
Configurations.setHelper(new FineConfigurationHelper());
EventDispatcher.fire(ConfigEvent.READY);
// 固化一些配置
FinalPreferenceConfig.solidify();
InsecurityElementFactory.setConfigInsecurityElementProvider(ConfigInsecurityElementProviderImpl.INSTANCE);
}
private void stopConfConfig() {
DaoContext.setClassHelperDao(null);
DaoContext.setEntityDao(null);
DaoContext.setXmlEntityDao(null);
Configurations.setHelper(null);
}
/**
* --------- core-supplemental --------
*/
private void startCorePrepare() {
if (WorkContext.getCurrent().isLocal()) {
EncryptionInitialization.getInstance().init();
EncryptionScaffold.setSecuritySeedProvider(new SecuritySeedProvider() {
@Override
public byte[] getSeed() {
return LoadSeedSecurityKey.getInstance().loadSeedFile();
}
@Override
public void resetSeed() {
LoadSeedSecurityKey.getInstance().reset();
}
});
LoadSeedSecurityKey.getInstance().init();
} else {
// 远程也先写死加解密,放在内存中就好,fbp那边暂时没有提供扩展,两边都是写死的,等他们提供扩展后设计器再适配
SystemEncryptionManager.getInstance().restore();
}
}
private void stopCorePrepare() {
EncryptionScaffold.setSecuritySeedProvider(new SecuritySeedProvider() {});
LoadSeedSecurityKey.getInstance().reset();
}
/**
* --------- EnvPrepare ---------
*/
private void stopEnvPrepare() {
EnvDetectorCenter.getInstance().destroy();
}
private void startEnvPrepare() {
/// 环境检测、资源升级都暂不支持
//EnvDetectorCenter.getInstance().init();
if (WorkContext.getCurrent().isLocal()) {
// 如果是切回本地,要初始化成本地仓库
// 如果是切回远程,会在用户创建的时候就同步初始化远程仓库
RepositoryManager.getInstance().initLocalRepository();
}
}
}