/* * Copyright 2013 The Solmix Project * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.gnu.org/licenses/ * or see the FSF site: http://www.fsf.org. */ package org.solmix.mybatis; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Resource; import javax.sql.DataSource; import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.executor.ErrorContext; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.solmix.api.exception.SlxException; import org.solmix.api.types.Texception; import org.solmix.api.types.Tmodule; import org.solmix.commons.collections.DataTypeMap; import org.solmix.commons.util.DataUtils; import org.solmix.runtime.SystemContext; import org.solmix.runtime.cm.ConfigureUnit; import org.solmix.runtime.cm.ConfigureUnitManager; import org.solmix.sql.ConnectionManager; import org.solmix.sql.SQLDataSource; /** * * @author solmix.f@gmail.com * @version $Id$ 2014年7月10日 */ public abstract class AbstractSqlSessionFactoryProvider implements SqlSessionFactoryProvider { protected final Map<String, SqlSessionFactoryHolder> _tempCache = new ConcurrentHashMap<String, SqlSessionFactoryHolder>(); private final Logger LOG = LoggerFactory.getLogger(AbstractSqlSessionFactoryProvider.class.getName()); protected SystemContext sc; public AbstractSqlSessionFactoryProvider(final SystemContext sc) { setSystemContext(sc); } /** * @param systemContext */ @Resource public void setSystemContext(final SystemContext systemcontext) { this.sc = systemcontext; if (sc != null) { sc.setExtension(this, SqlSessionFactoryProvider.class); } } protected DataTypeMap getConfig() throws SlxException { ConfigureUnitManager cum = sc.getExtension(ConfigureUnitManager.class); ConfigureUnit cu = null; try { cu = cum.getConfigureUnit(MybatisDataSource.SERVICE_PID); } catch (IOException e) { throw new SlxException(Tmodule.SQL, Texception.IO_EXCEPTION, e); } if (cu != null) return cu.getProperties(); else return new DataTypeMap(); } /** * {@inheritDoc} * @throws SlxException * * @see org.solmix.mybatis.SqlSessionFactoryProvider#createSqlSessionFactory(java.lang.String) */ @Override public SqlSessionFactory createSqlSessionFactory(String environment, Map<String, Object> properties) throws SlxException { SqlSessionFactoryHolder sessionFactory = _tempCache.get(environment); if (sessionFactory != null) { return sessionFactory.factory; } if (LOG.isTraceEnabled()) LOG.trace("Building Mybatis SqlSessionFactory for environment '" + environment + "'"); SqlSessionFactoryHolder session = null; session = createSessionForDb(environment, properties); if (session != null) _tempCache.put(environment, session); return session.factory; } public String getDatabaseType(String dbName){ ConfigureUnitManager cum = sc.getExtension(ConfigureUnitManager.class); ConfigureUnit cu = null; try { cu = cum.getConfigureUnit(SQLDataSource.SERVICE_PID); } catch (IOException e) { throw new java.lang.IllegalStateException( e); } if(cu!=null){ DataTypeMap types= cu.getProperties(); return types.getString(dbName+".database.type"); } return null; } protected abstract InputStream getConfigAsStream(String environemnt,String configLocation) throws IOException; /** * @param dbName * @return * @throws SlxException */ private synchronized SqlSessionFactoryHolder createSessionForDb(String environment, Map<String, Object> properties) throws SlxException { DataTypeMap config = getConfig(); DataTypeMap dbConfig = config.getSubtree(environment); if(dbConfig.isEmpty()){ throw new java.lang.NullPointerException("Mybatis Environment is not Configured!"); } try { String configLocation = dbConfig.getString("mybatis.config.file"); String dbName = dbConfig.getString("mybatis.dbname").trim(); String dbType = getDatabaseType(dbName); String mapperScan = dbConfig.getString("mybatis.mapper.scan.base"); Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; if (DataUtils.isNotNullAndEmpty(configLocation)) { InputStream inputStream =getConfigAsStream(environment,configLocation); xmlConfigBuilder = new XMLConfigBuilder(inputStream, null, createPropertiesFromMap(properties)); configuration = xmlConfigBuilder.getConfiguration(); } else { throw new SlxException( "Failed to instance Mybatis Configuration,because of resource file is null"); } configuration.addInterceptor(new PageInterceptor()); if (LOG.isDebugEnabled()) { LOG.debug("Registered plugin: '" + PageInterceptor.class.getName() + "'"); } if (xmlConfigBuilder != null) { try { xmlConfigBuilder.parse(); if (LOG.isDebugEnabled()) { LOG.debug("Parsed configuration file: '" + configLocation + "'"); } } catch (Exception ex) { throw new SlxException(Tmodule.DATASOURCE, Texception.DS_DSCONFIG_ERROR, "Failed to parse config resource: " + configLocation, ex); } finally { ErrorContext.instance().reset(); } } ConnectionManager conn = getConnectionManager(sc); DataSource dataSource = conn.getDataSource(dbName); Environment env = new Environment(environment, new JdbcTransactionFactory(), dataSource); configuration.setEnvironment(env); Map<String,InputStream> mapperLocations = getMapperResources(environment,mapperScan); if (!mapperLocations.isEmpty()) { for (String key : mapperLocations.keySet()) { if (mapperLocations.get(key) == null) { continue; } try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder( mapperLocations.get(key), configuration, key, configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new IOException( "Failed to parse mapping resource: '" + key + "'", e); } finally { ErrorContext.instance().reset(); } if (LOG.isDebugEnabled()) { LOG.debug("Parsed mapper file: '" + key + "'"); } } } else { if (LOG.isDebugEnabled()) { LOG.debug("Property 'mapperLocations' was not specified or no matching resources found"); } } SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(configuration); return new SqlSessionFactoryHolder(factory, dbType); } catch (IOException e) { throw new SlxException("Failed to create mybatis sqlSessionFactory",e); } } protected abstract Map<String,InputStream> getMapperResources(String environment,String mapperLocations)throws IOException; protected ConnectionManager getConnectionManager(SystemContext sc) { return sc.getExtension(ConnectionManager.class); } public static Properties createPropertiesFromMap(Map<String, Object> propMap) { if (propMap == null) return null; Properties result = new Properties(); for (Iterator<String> i = propMap.keySet().iterator(); i.hasNext();) { String key = i.next(); Object val = propMap.get(key); if (key != null && val != null) result.put(key, val); } return result; } /** * {@inheritDoc} * * @see org.solmix.mybatis.SqlSessionFactoryProvider#createSqlSessionFactory(java.lang.String, * java.util.Map) */ @Override public SqlSessionFactory createSqlSessionFactory(String environment) throws SlxException{ return createSqlSessionFactory(environment, null); } private class SqlSessionFactoryHolder{ SqlSessionFactory factory; String dbType; SqlSessionFactoryHolder(SqlSessionFactory factory,String dbType){ this.factory=factory; this.dbType=dbType; } } /** * {@inheritDoc} * * @see org.solmix.mybatis.SqlSessionFactoryProvider#getDbType(java.lang.String) */ @Override public String getDbType(String environment) { SqlSessionFactoryHolder sessionFactory = _tempCache.get(environment); if (sessionFactory != null) { return sessionFactory.dbType; } DataTypeMap config; try { config = getConfig(); } catch (SlxException e) { throw new java.lang.IllegalStateException("Mybatis config is null",e); } DataTypeMap dbConfig = config.getSubtree(environment); return dbConfig.getString("mybatis.dbtype").trim(); } }