package ddth.dasp.handlersocket.bo.hs; import java.io.InputStream; import java.lang.reflect.Array; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentMap; import org.apache.commons.lang3.StringUtils; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.MapMaker; import ddth.dasp.common.utils.JsonUtils; import ddth.dasp.common.utils.OsgiUtils; import ddth.dasp.common.utils.PropsUtils; import ddth.dasp.framework.bo.CachedBoManager; import ddth.dasp.framework.bo.jdbc.BaseJdbcBoManager; import ddth.dasp.framework.utils.EhProperties; import ddth.dasp.handlersocket.hsc.IHsc; import ddth.dasp.handlersocket.hsc.IHscFactory; public abstract class BaseHsBoManager extends CachedBoManager implements IHsBoManager { private final static int NUM_PROCESSORS = Runtime.getRuntime() .availableProcessors(); @SuppressWarnings("unchecked") private final static Map<String, Object>[] MAP_ARRAY = (Map<String, Object>[]) Array .newInstance(Map.class, 0); private Logger LOGGER = LoggerFactory.getLogger(BaseJdbcBoManager.class); private IHscFactory hscFactory; private String dbHost; private int dbPort; private boolean dbReadOnly = false; private Properties queryConfig = new EhProperties(); private ConcurrentMap<String, QueryConfig> cacheQueryConfig = new MapMaker() .concurrencyLevel(NUM_PROCESSORS).makeMap(); private Object queryConfigLocation; protected IHscFactory getHscFactory() { if (hscFactory != null) { return hscFactory; } BundleContext bundleContext = getBundleContext(); if (bundleContext != null) { OsgiUtils.getService(bundleContext, IHscFactory.class); } return null; } public void setHscFactory(IHscFactory hscFactory) { this.hscFactory = hscFactory; } protected String getDbHost() { return dbHost; } public void setDbHost(String dbHost) { this.dbHost = dbHost; } protected int getDbPort() { return dbPort; } public void setDbPort(int dbPort) { this.dbPort = dbPort; } protected boolean isDbReadOnly() { return dbReadOnly; } public void setDbReadOnly(boolean dbReadOnly) { this.dbReadOnly = dbReadOnly; } /** * Initializing method. */ public void init() { loadQueryConfig(); } /** * Destruction method. */ public void destroy() { // EMPTY } /** * Loads SQL properties. It's in {@link Properties} format. */ protected void loadQueryConfig() { this.queryConfig.clear(); this.cacheQueryConfig.clear(); Object queryConfig = getQueryConfigLocation(); if (queryConfig instanceof Properties) { this.queryConfig.putAll((Properties) queryConfig); } else if (queryConfig instanceof InputStream) { Properties props = PropsUtils .loadProperties((InputStream) queryConfig); if (props != null) { this.queryConfig.putAll(props); } } else if (queryConfig != null) { String location = queryConfig.toString(); InputStream is = getClass().getResourceAsStream(location); Properties props = PropsUtils.loadProperties(is, location.endsWith(".xml")); if (props != null) { this.queryConfig.putAll(props); } } else { String msg = "Can not load query configuration from [" + queryConfig + "]!"; LOGGER.warn(msg); } } /** * Gets the query configuration location. The location can be either of: * * <ul> * <li>{@link InputStream}: properties are loaded from the input stream.</li> * <li>{@link Properties}: properties are copied from this one.</li> * <li>{@link String}: properties are loaded from file (located within the * classpath) specified by this string.</li> * </ul> * * @return location of the SQL properties */ protected Object getQueryConfigLocation() { return queryConfigLocation; } /** * Sets the query configuration location. The location can be either of: * * <ul> * <li>{@link InputStream}: properties are loaded from the input stream.</li> * <li>{@link Properties}: properties are copied from this one.</li> * <li>{@link String}: properties are loaded from file (located within the * classpath) specified by this string.</li> * </ul> * * @param queryConfigLocation */ public void setQueryConfigLocation(Object queryConfigLocation) { this.queryConfigLocation = queryConfigLocation; } /** * Gets a SQL property by name. * * @param name * @return */ @SuppressWarnings("unchecked") protected QueryConfig getQueryConfig(String name) { QueryConfig result = cacheQueryConfig.get(name); if (result == null) { String rawProps = queryConfig.getProperty(name); if (!StringUtils.isBlank(rawProps)) { try { Map<String, Object> props = JsonUtils.fromJson(rawProps, Map.class); result = new QueryConfig(); result.populate(props); cacheQueryConfig.put(name, result); } catch (Exception e) { LOGGER.warn(e.getMessage(), e); result = null; } } } return result; } /** * {@inheritDoc} */ @Override public IHsc getConnection() { IHsc hsc = getHscFactory().getConnection(dbHost, dbPort, !dbReadOnly); return hsc; } /** * {@inheritDoc} */ @Override public void releaseConnection(IHsc conn) { getHscFactory().releaseConnection(conn); } private String replace(String str, Object[] replacements) { for (int i = 1; i < replacements.length; i++) { str = str.replaceAll("\\{" + i + "\\}", replacements[i] != null ? replacements[i].toString() : ""); } return str; } /** * Obtains and builds the {@link QueryConfig}. * * @param configKey * @return */ protected QueryConfig buildQueryConfig(final Object configKey) { final String finalKey = (configKey instanceof Object[]) ? ((Object[]) configKey)[0] .toString() : configKey.toString(); QueryConfig queryConfig = null; QueryConfig tempQueryConfig = getQueryConfig(finalKey); if (tempQueryConfig != null) { queryConfig = tempQueryConfig.clone(); } if (queryConfig != null && configKey instanceof Object[]) { Object[] temp = (Object[]) configKey; String dbName = queryConfig.getDbName(); queryConfig.setDbName(replace(dbName, temp)); String indexName = queryConfig.getIndexName(); queryConfig.setIndexName(replace(indexName, temp)); String tableName = queryConfig.getTableName(); queryConfig.setTableName(replace(tableName, temp)); } return queryConfig; } /** * Executes a SELECT query, without cache & paging. * * @param configKey * @param findValues * @return * @throws SQLException */ protected Map<String, Object>[] execSelect(final Object configKey, Object[] findValues) throws SQLException { return execSelect(configKey, findValues, (String) null); } /** * Executes a SELECT query, without paging. * * @param configKey * @param findValues * @param cacheKey * @return * @throws SQLException */ protected Map<String, Object>[] execSelect(final Object configKey, Object[] findValues, String cacheKey) throws SQLException { return execSelect(configKey, findValues, cacheKey, Integer.MAX_VALUE); } /** * Executes a SELECT query, and limits number of returned rows. * * @param configKey * @param findValues * @param cacheKey * @param limitRows * @return * @throws SQLException */ protected Map<String, Object>[] execSelect(final Object configKey, Object[] findValues, String cacheKey, int limitRows) throws SQLException { return execSelect(configKey, findValues, cacheKey, Integer.MAX_VALUE, 0); } /** * Executes a SELECT query. * * @param configKey * @param findValues * @param cacheKey * @param limitRows * @param rowOffset * @return * @throws SQLException */ @SuppressWarnings("unchecked") protected Map<String, Object>[] execSelect(final Object configKey, Object[] findValues, String cacheKey, int limitRows, int rowOffset) throws SQLException { List<Map<String, Object>> result = null; if (!StringUtils.isBlank(cacheKey) && cacheEnabled()) { // get from cache result = (List<Map<String, Object>>) getFromCache(cacheKey); } if (result == null) { // cache missed QueryConfig queryConfig = buildQueryConfig(configKey); if (queryConfig == null) { throw new SQLException("Can not retrieve query configuration [" + configKey + "]!"); } IHsc conn = getConnection(); if (conn == null) { throw new SQLException("Can not make connection to database!"); } ResultSet resultSet = null; result = new ArrayList<Map<String, Object>>(); try { String dbName = queryConfig.getDbName(); String tableName = queryConfig.getTableName(); String tableIndexName = queryConfig.getIndexName(); String[] queryColumns = queryConfig.getColumnNames(); resultSet = conn.select(dbName, tableName, tableIndexName, queryColumns, findValues); ColumnConfig[] columns = queryConfig.getColumns(); while (resultSet.next()) { Map<String, Object> obj = new HashMap<String, Object>(); for (int i = 1; i <= columns.length; i++) { String colName = columns[i - 1].getMappedName(); Object value = columns[i - 1].getValue(resultSet); obj.put(colName, value); } result.add(obj); } } finally { if (resultSet != null) { try { resultSet.close(); } catch (Exception e) { } } releaseConnection(conn); } } if (!StringUtils.isBlank(cacheKey) && cacheEnabled()) { // put to cache putToCache(cacheKey, result); } return result.toArray(MAP_ARRAY); } /** * Execute an INSERT statement. * * @param configKey * @param values * @return * @throws SQLException */ protected boolean execInsert(final Object configKey, Object[] values) throws SQLException { QueryConfig queryConfig = buildQueryConfig(configKey); if (queryConfig == null) { throw new SQLException("Can not retrieve query configuration [" + configKey + "]!"); } String dbName = queryConfig.getDbName(); String tableName = queryConfig.getTableName(); String tableIndexName = queryConfig.getIndexName(); String[] queryColumns = queryConfig.getColumnNames(); IHsc conn = getConnection(); if (conn == null) { throw new SQLException("Can not make connection to database!"); } try { return conn.insert(dbName, tableName, tableIndexName, queryColumns, values); } finally { releaseConnection(conn); } } /** * Executes a UPDATE statement. * * @param configKey * @param values * @param findValues * @return * @throws SQLException */ protected int execUpdate(final Object configKey, Object[] values, Object[] findValues) throws SQLException { QueryConfig queryConfig = buildQueryConfig(configKey); if (queryConfig == null) { throw new SQLException("Can not retrieve query configuration [" + configKey + "]!"); } String dbName = queryConfig.getDbName(); String tableName = queryConfig.getTableName(); String tableIndexName = queryConfig.getIndexName(); String[] queryColumns = queryConfig.getColumnNames(); IHsc conn = getConnection(); if (conn == null) { throw new SQLException("Can not make connection to database!"); } try { return conn.update(dbName, tableName, tableIndexName, queryColumns, values, findValues); } finally { releaseConnection(conn); } } protected int execDelete(final Object configKey, Object[] findValues) throws SQLException { QueryConfig queryConfig = buildQueryConfig(configKey); if (queryConfig == null) { throw new SQLException("Can not retrieve query configuration [" + configKey + "]!"); } String dbName = queryConfig.getDbName(); String tableName = queryConfig.getTableName(); String tableIndexName = queryConfig.getIndexName(); String[] queryColumns = queryConfig.getColumnNames(); IHsc conn = getConnection(); if (conn == null) { throw new SQLException("Can not make connection to database!"); } try { return conn.delete(dbName, tableName, tableIndexName, queryColumns, findValues); } finally { releaseConnection(conn); } } }