Java tutorial
/* * Copyright (C) 2010-2101 Alibaba Group Holding Limited. * * 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.alibaba.otter.node.etl.common.datasource.impl; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import com.alibaba.otter.common.push.datasource.DataSourceHanlder; import com.alibaba.otter.node.etl.common.datasource.DataSourceService; import com.alibaba.otter.shared.common.model.config.data.DataMediaSource; import com.alibaba.otter.shared.common.model.config.data.DataMediaType; import com.alibaba.otter.shared.common.model.config.data.db.DbMediaSource; import com.google.common.base.Function; import com.google.common.collect.GenericMapMaker; import com.google.common.collect.MapEvictionListener; import com.google.common.collect.MapMaker; /** * Comment of DataSourceServiceImpl * * @author xiaoqing.zhouxq * @author zebinxu, add {@link DataSourceHanlder} */ public class DBDataSourceService implements DataSourceService, DisposableBean { private static final Logger logger = LoggerFactory.getLogger(DBDataSourceService.class); private List<DataSourceHanlder> dataSourceHandlers; private int maxWait = 60 * 1000; private int minIdle = 0; private int initialSize = 0; private int maxActive = 32; private int maxIdle = 32; private int numTestsPerEvictionRun = -1; private int timeBetweenEvictionRunsMillis = 60 * 1000; private int removeAbandonedTimeout = 5 * 60; private int minEvictableIdleTimeMillis = 5 * 60 * 1000; /** * pipeline?DataSource.<br> * key = pipelineId<br> * value = key(dataMediaSourceId)-value(DataSource)<br> */ private Map<Long, Map<DbMediaSource, DataSource>> dataSources; public DBDataSourceService() { // soft GenericMapMaker mapMaker = new MapMaker().softValues(); mapMaker = ((MapMaker) mapMaker) .evictionListener(new MapEvictionListener<Long, Map<DbMediaSource, DataSource>>() { public void onEviction(Long pipelineId, Map<DbMediaSource, DataSource> dataSources) { if (dataSources == null) { return; } for (DataSource dataSource : dataSources.values()) { // for filter to destroy custom datasource if (letHandlerDestroyIfSupport(pipelineId, dataSource)) { continue; } BasicDataSource basicDataSource = (BasicDataSource) dataSource; try { basicDataSource.close(); } catch (SQLException e) { logger.error("ERROR ## close the datasource has an error", e); } } } }); // map dataSources = new MapMaker().makeComputingMap(new Function<Long, Map<DbMediaSource, DataSource>>() { public Map<DbMediaSource, DataSource> apply(final Long pipelineId) { // map return new MapMaker().makeComputingMap(new Function<DbMediaSource, DataSource>() { public DataSource apply(DbMediaSource dbMediaSource) { // ,? dataSource DataSource customDataSource = preCreate(pipelineId, dbMediaSource); if (customDataSource != null) { return customDataSource; } return createDataSource(dbMediaSource.getUrl(), dbMediaSource.getUsername(), dbMediaSource.getPassword(), dbMediaSource.getDriver(), dbMediaSource.getType(), dbMediaSource.getEncode()); } }); } }); } public DataSource getDataSource(long pipelineId, DataMediaSource dataMediaSource) { Assert.notNull(dataMediaSource); return dataSources.get(pipelineId).get(dataMediaSource); } public void destroy(Long pipelineId) { Map<DbMediaSource, DataSource> sources = dataSources.remove(pipelineId); if (sources != null) { for (DataSource source : sources.values()) { try { // for filter to destroy custom datasource if (letHandlerDestroyIfSupport(pipelineId, source)) { continue; } // fallback for regular destroy // TODO need to integrate to handler BasicDataSource basicDataSource = (BasicDataSource) source; basicDataSource.close(); } catch (SQLException e) { logger.error("ERROR ## close the datasource has an error", e); } } sources.clear(); } } private boolean letHandlerDestroyIfSupport(Long pipelineId, DataSource dataSource) { boolean destroied = false; if (CollectionUtils.isEmpty(this.dataSourceHandlers)) { return destroied; } for (DataSourceHanlder handler : this.dataSourceHandlers) { if (handler.support(dataSource)) { handler.destory(pipelineId); destroied = true; return destroied; } } return destroied; } public void destroy() throws Exception { for (Long pipelineId : dataSources.keySet()) { destroy(pipelineId); } } private DataSource createDataSource(String url, String userName, String password, String driverClassName, DataMediaType dataMediaType, String encoding) { BasicDataSource dbcpDs = new BasicDataSource(); dbcpDs.setInitialSize(initialSize);// ? dbcpDs.setMaxActive(maxActive);// ????? dbcpDs.setMaxIdle(maxIdle);// ?? dbcpDs.setMinIdle(minIdle);// ?0? dbcpDs.setMaxWait(maxWait);// ??-1? dbcpDs.setRemoveAbandoned(true);// ??removeAbandonedTimeout dbcpDs.setLogAbandoned(true);// ?? dbcpDs.setRemoveAbandonedTimeout(removeAbandonedTimeout); // ? dbcpDs.setNumTestsPerEvictionRun(numTestsPerEvictionRun);// ?? dbcpDs.setTestOnBorrow(false);// ?? dbcpDs.setTestOnReturn(false);// ?? dbcpDs.setTestWhileIdle(true);// ???? dbcpDs.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); // ???????? dbcpDs.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); // ??????? // ?? dbcpDs.setDriverClassName(driverClassName); dbcpDs.setUrl(url); dbcpDs.setUsername(userName); dbcpDs.setPassword(password); if (dataMediaType.isOracle()) { dbcpDs.addConnectionProperty("restrictGetTables", "true"); dbcpDs.setValidationQuery("select 1 from dual"); } else if (dataMediaType.isMysql()) { // open the batch mode for mysql since 5.1.8 dbcpDs.addConnectionProperty("useServerPrepStmts", "false"); dbcpDs.addConnectionProperty("rewriteBatchedStatements", "true"); dbcpDs.addConnectionProperty("zeroDateTimeBehavior", "convertToNull");// 0000-00-00null dbcpDs.addConnectionProperty("yearIsDateType", "false");// ??year?date? dbcpDs.addConnectionProperty("noDatetimeStringSync", "true");// ,??? if (StringUtils.isNotEmpty(encoding)) { if (StringUtils.equalsIgnoreCase(encoding, "utf8mb4")) { dbcpDs.addConnectionProperty("characterEncoding", "utf8"); dbcpDs.setConnectionInitSqls(Arrays.asList("set names utf8mb4")); } else { dbcpDs.addConnectionProperty("characterEncoding", encoding); } } dbcpDs.setValidationQuery("select 1"); } else { logger.error("ERROR ## Unknow database type"); } return dbcpDs; } /** * ,? dataSource */ private DataSource preCreate(Long pipelineId, DbMediaSource dbMediaSource) { if (CollectionUtils.isEmpty(dataSourceHandlers)) { return null; } DataSource dataSource = null; for (DataSourceHanlder handler : dataSourceHandlers) { if (handler.support(dbMediaSource)) { dataSource = handler.create(pipelineId, dbMediaSource); if (dataSource != null) { return dataSource; } } } return null; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { this.numTestsPerEvictionRun = numTestsPerEvictionRun; } public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { this.removeAbandonedTimeout = removeAbandonedTimeout; } public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } public void setDataSourceHandlers(List<DataSourceHanlder> dataSourceHandlers) { this.dataSourceHandlers = dataSourceHandlers; } }