package com.ctrip.platform.dal.dao; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import com.ctrip.platform.dal.dao.client.DalHA; import com.ctrip.platform.dal.exceptions.DalException; /** * Additional parameters used to indicate how DAL behaves for each of the operation. * * IMPORTANT NOTE!!! * Because entry may be changed by by DAL internal logic, DalHints is not intended to be reused. * You should never create a class level DalHints reference and reuse it in the following calls. * * @author jhhe */ public class DalHints { private Map<DalHintEnum, Object> hints = new ConcurrentHashMap<DalHintEnum, Object>(); // It is not so nice to put keyholder here, but to make Task stateless, I have no other choice private KeyHolder keyHolder; private static final Object NULL = new Object(); public KeyHolder getKeyHolder() { return keyHolder; } public DalHints setKeyHolder(KeyHolder keyHolder) { this.keyHolder = keyHolder; return this; } public static DalHints createIfAbsent(DalHints hints) { return hints == null ? new DalHints() : hints; } public DalHints clone() { DalHints newHints = new DalHints(); newHints.hints.putAll(hints); // Make sure we do deep copy for Map Map shardColValues = (Map)newHints.get(DalHintEnum.shardColValues); if(shardColValues != null) newHints.setShardColValues(new HashMap<String, Object>(shardColValues)); // Make sure we do deep copy for Map Map fields = (Map)newHints.get(DalHintEnum.fields); if(fields != null) newHints.setFields(new LinkedHashMap<String, Object>(fields)); newHints.keyHolder = keyHolder; return newHints; } public DalHints() {} /** * Make sure only shardId, tableShardId, shardValue, shardColValue will be used to locate shard Id. */ public DalHints cleanUp() { hints.remove(DalHintEnum.fields); hints.remove(DalHintEnum.parameters); return this; } public DalHints(DalHintEnum...hints) { for(DalHintEnum hint: hints) { set(hint); } } public boolean is(DalHintEnum hint) { return hints.containsKey(hint); } public Object get(DalHintEnum hint) { return hints.get(hint); } public DalHA getHA(){ return (DalHA)hints.get(DalHintEnum.heighAvaliable); } public DalHints setHA(DalHA ha){ hints.put(DalHintEnum.heighAvaliable, ha); return this; } public Integer getInt(DalHintEnum hint, int defaultValue) { Object value = hints.get(hint); if(value == null) return defaultValue; return (Integer)value; } public Integer getInt(DalHintEnum hint) { return (Integer)hints.get(hint); } public String getString(DalHintEnum hint) { Object value = hints.get(hint); if(value == null) return null; if(value instanceof String) return (String)value; return value.toString(); } public Set<String> getStringSet(DalHintEnum hint) { return (Set<String>)hints.get(hint); } public DalHints set(DalHintEnum hint) { set(hint, NULL); return this; } public DalHints set(DalHintEnum hint, Object value) { hints.put(hint, value); return this; } public DalHints setIfAbsent(DalHintEnum hint, Object value) { if(is(hint)) return this; hints.put(hint, value); return this; } public DalHints inDatabase(String databaseName) { hints.put(DalHintEnum.designatedDatabase, databaseName); return this; } public DalHints inShard(String shardId) { hints.put(DalHintEnum.shard, shardId); return this; } public DalHints inShard(Integer shardId) { hints.put(DalHintEnum.shard, shardId); return this; } public DalHints inTableShard(String tableShardId) { hints.put(DalHintEnum.tableShard, tableShardId); return this; } public DalHints inTableShard(Integer tableShardId) { hints.put(DalHintEnum.tableShard, tableShardId); return this; } public String getShardId() { return getString(DalHintEnum.shard); } public String getTableShardId() { return getString(DalHintEnum.tableShard); } public DalHints setShardValue(Object shardValue) { return set(DalHintEnum.shardValue, shardValue); } public DalHints setTableShardValue(Object tableShardValue) { return set(DalHintEnum.tableShardValue, tableShardValue); } public DalHints setShardColValues(Map<String, ?> shardColValues) { return set(DalHintEnum.shardColValues, shardColValues); } public DalHints setShardColValue(String column, Object value) { if(is(DalHintEnum.shardColValues) == false) { setShardColValues(new HashMap<String, Object>()); } Map<String, Object> shardColValues = (Map<String, Object>)get(DalHintEnum.shardColValues); shardColValues.put(column, value); return this; } public DalHints setFields(Map<String, ?> fields) { if(fields == null) return this; return set(DalHintEnum.fields, fields); } public DalHints setParameters(StatementParameters parameters) { if(parameters == null) return this; return set(DalHintEnum.parameters, parameters); } public DalHints inAllShards() { set(DalHintEnum.allShards); return this; } public boolean isAllShards() { return is(DalHintEnum.allShards); } public DalHints inShards(Set<String> shards) { hints.put(DalHintEnum.shards, shards); return this; } public boolean isInShards() { return is(DalHintEnum.shards); } public Set<String> getShards() { return (Set<String>)hints.get(DalHintEnum.shards); } public DalHints shardBy(String parameterName) { hints.put(DalHintEnum.shardBy, parameterName); return this; } public String getShardBy() { return (String)hints.get(DalHintEnum.shardBy); } public boolean isShardBy() { return is(DalHintEnum.shardBy); } public <T> DalHints mergeBy(ResultMerger<T> merger) { hints.put(DalHintEnum.resultMerger, merger); return this; } public <T> DalHints sortBy(Comparator<T> sorter) { hints.put(DalHintEnum.resultSorter, sorter); return this; } public <T> Comparator<T> getSorter() { return (Comparator<T>)get(DalHintEnum.resultSorter); } public <T> DalHints sequentialExecute() { set(DalHintEnum.sequentialExecution); return this; } public DalHints masterOnly() { set(DalHintEnum.masterOnly, true); return this; } // public DalHints slaveOnly() { // set(DalHintEnum.masterOnly, false); // return this; // } // public DalHints continueOnError() { set(DalHintEnum.continueOnError); return this; } public DalHints asyncExecution() { set(DalHintEnum.asyncExecution); return this; } /** * If asyncExecution is set or there is callback, we assume it is asynchronized execution. * And in this case the futureResult will always be populated with Future. * If there is callback, the result will be pass to callback also. * * @return */ public boolean isAsyncExecution() { return is(DalHintEnum.asyncExecution) || is(DalHintEnum.resultCallback); } public Future<?> getAsyncResult() { return (Future<?>)get(DalHintEnum.futureResult); } public <T> T getResult() throws Exception { return (T)((Future<?>)get(DalHintEnum.futureResult)).get(); } public int getIntResult() throws Exception { Object result = ((Future<?>)get(DalHintEnum.futureResult)).get(); if(result instanceof Number) return ((Number)result).intValue(); // Assume it is int[] return ((int[])result)[0]; } public Integer getIntegerResult() throws Exception { return (Integer)getResult(); } public int[] getIntArrayResult() throws Exception { return (int[])((Future<?>)get(DalHintEnum.futureResult)).get(); } public <T> List<T> getListResult() throws Exception { return (List<T>)((Future<?>)get(DalHintEnum.futureResult)).get(); } public DalHints callbackWith(DalResultCallback callback) { set(DalHintEnum.resultCallback, callback); return this; } public boolean isStopOnError() { return !is(DalHintEnum.continueOnError); } public void handleError(String msg, Throwable e) throws DalException { // Just make sure error is not swallowed by us DalClientFactory.getDalLogger().error(msg, e); if(isStopOnError()) throw DalException.wrap(e); } public DalHints setIsolationLevel(int isolationLevel) { set(DalHintEnum.isolationLevel, isolationLevel); return this; } public DalHints forceAutoCommit() { set(DalHintEnum.forceAutoCommit); return this; } public DalHints timeout(int seconds) { set(DalHintEnum.timeout, seconds); return this; } public DalHints enableIdentityInsert() { set(DalHintEnum.enableIdentityInsert); return this; } public boolean isIdentityInsertDisabled() { return !is(DalHintEnum.enableIdentityInsert); } public DalHints updateNullField() { set(DalHintEnum.updateNullField); return this; } public boolean isUpdateNullField() { return is(DalHintEnum.updateNullField); } public DalHints updateUnchangedField() { set(DalHintEnum.updateUnchangedField); return this; } public boolean isUpdateUnchangedField() { return is(DalHintEnum.updateUnchangedField); } public DalHints insertNullField() { set(DalHintEnum.insertNullField); return this; } public boolean isInsertNullField() { return is(DalHintEnum.insertNullField); } public DalHints retrieveAllResultsFromSp() { return set(DalHintEnum.retrieveAllSpResults); } public DalHints include(Set<String> columns) { return set(DalHintEnum.includedColumns, columns); } public DalHints exclude(Set<String> columns) { return set(DalHintEnum.excludedColumns, columns); } public DalHints include(String... columns) { return set(DalHintEnum.includedColumns, new HashSet<>(Arrays.asList(columns))); } public DalHints exclude(String... columns) { return set(DalHintEnum.excludedColumns, new HashSet<>(Arrays.asList(columns))); } public Set<String> getIncluded() { return getStringSet(DalHintEnum.includedColumns); } public Set<String> getExcluded() { return getStringSet(DalHintEnum.excludedColumns); } public DalHints ignoreMissingFields() { return set(DalHintEnum.ignoreMissingFields, true); } public DalHints partialQuery(Set<String> columns) { return set(DalHintEnum.partialQuery, columns); } public DalHints partialQuery(String... columns) { return set(DalHintEnum.partialQuery, new HashSet<>(Arrays.asList(columns))); } public String[] getPartialQueryColumns() { return getStringSet(DalHintEnum.partialQuery).toArray(new String[getStringSet(DalHintEnum.partialQuery).size()]); } }