Java tutorial
/* ' * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * 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 jef.database; import java.io.IOException; import java.io.Serializable; import java.io.StringReader; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.SQLTimeoutException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import javax.persistence.EntityExistsException; import javax.persistence.FetchType; import javax.persistence.PersistenceException; import javax.persistence.QueryTimeoutException; import javax.sql.DataSource; import org.apache.commons.lang.ObjectUtils; import com.google.common.base.Objects; import jef.accelerator.bean.BeanAccessor; import jef.accelerator.bean.FastBeanWrapperImpl; import jef.common.log.LogUtil; import jef.database.Session.UpdateContext; import jef.database.annotation.Cascade; import jef.database.annotation.JoinType; import jef.database.datasource.DataSourceInfo; import jef.database.datasource.IRoutingDataSource; import jef.database.datasource.SimpleDataSource; import jef.database.dialect.DatabaseDialect; import jef.database.dialect.type.ColumnMapping; import jef.database.innerpool.PartitionSupport; import jef.database.jsqlparser.parser.JpqlParser; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.parser.StSqlParser; import jef.database.jsqlparser.parser.TokenMgrError; import jef.database.jsqlparser.statement.create.ColumnDefinition; import jef.database.jsqlparser.statement.create.CreateTable; import jef.database.jsqlparser.statement.select.OrderBy; import jef.database.jsqlparser.statement.select.Select; import jef.database.jsqlparser.visitor.Expression; import jef.database.jsqlparser.visitor.SelectItem; import jef.database.meta.AbstractMetadata; import jef.database.meta.AbstractRefField; import jef.database.meta.DbProperty; import jef.database.meta.ITableMetadata; import jef.database.meta.JoinKey; import jef.database.meta.JoinPath; import jef.database.meta.MetaHolder; import jef.database.meta.Reference; import jef.database.query.AbstractEntityMappingProvider; import jef.database.query.AbstractJoinImpl; import jef.database.query.ConditionQuery; import jef.database.query.DefaultPartitionCalculator; import jef.database.query.EntityMappingProvider; import jef.database.query.JoinElement; import jef.database.query.JoinUtil; import jef.database.query.JpqlExpression; import jef.database.query.OrderField; import jef.database.query.PartitionCalculator; import jef.database.query.Query; import jef.database.query.RefField; import jef.database.query.ReferenceType; import jef.database.query.SelectsImpl; import jef.database.query.SqlContext; import jef.database.query.SqlExpression; import jef.database.routing.PartitionResult; import jef.database.wrapper.executor.DbTask; import jef.tools.ArrayUtils; import jef.tools.Assert; import jef.tools.JefConfiguration; import jef.tools.StringUtils; import jef.tools.reflect.BeanWrapper; import jef.tools.reflect.GenericUtils; import jef.tools.security.cplus.TripleDES; import jef.tools.string.CharUtils; public final class DbUtils { // db rac????dbKeyracIdorm????racId // private static Map<String, String> dbKey2RacIds = new HashMap<String, // String>(); // private static Map<String, List<String>> racId2DbKeys = new // HashMap<String, List<String>>(); // private static ThreadLocal<Boolean> isRouted = new // ThreadLocal<Boolean>(); public static final int NO_RAC_ID = -1; public static PartitionCalculator partitionUtil = new DefaultPartitionCalculator(); /** * 1? 2?JTA????JTADDL??? * * 1?CPU2. 2?256 * 3?256??128??? */ public static ExecutorService es; static { int processorCount = Runtime.getRuntime().availableProcessors(); es = new ThreadPoolExecutor(processorCount * 2, processorCount * 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(processorCount * 4), Executors.defaultThreadFactory(), new CallerRunsPolicy()); } /** * ??,? * * @return * @throws IOException */ private static byte[] getEncryptKey() { String s = JefConfiguration.get(DbCfg.DB_ENCRYPTION_KEY); if (StringUtils.isEmpty(s)) { s = "781296-5e32-89122"; } return s.getBytes(); } /** * ? * * @param tasks * @throws SQLException */ public static void parallelExecute(List<DbTask> tasks) throws SQLException { CountDownLatch latch = new CountDownLatch(tasks.size()); Queue<SQLException> exceptions = new ConcurrentLinkedQueue<SQLException>(); Queue<Throwable> throwables = new ConcurrentLinkedQueue<Throwable>(); for (DbTask task : tasks) { task.prepare(latch, exceptions, throwables); DbUtils.es.execute(task); } try { latch.await(); } catch (InterruptedException e) { throw new SQLException(e); } if (!exceptions.isEmpty()) { throw DbUtils.wrapExceptions(exceptions); } if (!throwables.isEmpty()) { throw DbUtils.toRuntimeException(throwables.peek()); } } /* * ?SQL <strong>???</strong> * * @param e * * @param tablename * * @param conn */ public static void processError(SQLException e, String tablename, OperateTarget conn) { if (conn.getProfile().isIOError(e)) { conn.notifyDisconnect(e); } DebugUtil.setSqlState(e, tablename); } /** * * * @param class1 * @return */ public static Reference findPath(ITableMetadata from, ITableMetadata target) { for (Reference r : from.getRefFieldsByRef().keySet()) { if (r.getTargetType() == target) { return r; } } return null; } /** * ??0 * * @param class1 * @return * @throws IllegalArgumentException */ public static Reference findDistinctPath(ITableMetadata from, ITableMetadata target) { Reference ref = null; for (Reference reference : from.getRefFieldsByRef().keySet()) { if (reference.getTargetType() == target) { if (ref != null) { throw new IllegalArgumentException( "There's more than one reference to [" + target.getSimpleName() + "] in type [" + from.getSimpleName() + "],please assign the reference field name."); } ref = reference; } } if (ref == null) { throw new IllegalArgumentException("Target class " + target.getSimpleName() + "of fileter-condition is not referenced by " + from.getSimpleName()); } return ref; } /** * ??????? * * @param profile * @param name * @return */ public static final String escapeColumn(DatabaseDialect profile, String name) { if (name == null) return name; String w = profile.getProperty(DbProperty.WRAP_FOR_KEYWORD); if (w != null && profile.containKeyword(name)) { StringBuilder sb = new StringBuilder(name.length() + 2); sb.append(w.charAt(0)).append(name).append(w.charAt(1)); return sb.toString(); } return name; } /** * ?datasource?? * * @param ds * @param updateDataSourceProperties * ?ds?datasource * @return * @throws SQLException */ public static ConnectInfo tryAnalyzeInfo(DataSource ds, boolean updateDataSourceProperties) { if (ds instanceof IRoutingDataSource) { IRoutingDataSource rds = (IRoutingDataSource) ds; Entry<String, DataSource> e = rds.getDefaultDatasource(); if (e == null) {// ??DataSource Collection<String> names = rds.getDataSourceNames(); if (!names.isEmpty()) { String name = names.iterator().next(); LogUtil.warn("Can not determine default datasource name. choose [" + name + "] as default datasource."); return tryAnalyzeInfo(rds.getDataSource(name), updateDataSourceProperties); } } else { return tryAnalyzeInfo(e.getValue(), updateDataSourceProperties); } } if (ds instanceof DataSourceInfo) { DataSourceInfo dsw = (DataSourceInfo) ds; ConnectInfo info = new ConnectInfo(); DbUtils.processDataSourceOfEnCrypted(dsw); info.url = dsw.getUrl(); info.user = dsw.getUser(); info.password = dsw.getPassword(); DatabaseDialect profile = info.parse();// ?profile, ????? if (updateDataSourceProperties) profile.processConnectProperties(dsw); return info;// ? } return null; } /** * ??? * * @param conn * @return * @throws SQLException */ public static ConnectInfo tryAnalyzeInfo(Connection conn) throws SQLException { DatabaseMetaData meta = conn.getMetaData(); ConnectInfo info = new ConnectInfo(); info.user = meta.getUserName(); info.url = meta.getURL(); info.parse();// ?profile, ????? return info; } /** * Close the given JDBC Connection and ignore any thrown exception. This is * useful for typical finally blocks in manual JDBC code. * * @param con * the JDBC Connection to close (may be {@code null}) */ public static void closeConnection(Connection con) { if (con != null) { try { con.close(); } catch (SQLException ex) { LogUtil.exception("Could not close JDBC Connection", ex); } catch (Throwable ex) { LogUtil.exception("Unexpected exception on closing JDBC Connection", ex); } } } /** * SQL? * * @param errors * @return */ public static final SQLException wrapExceptions(Collection<SQLException> errors) { if (errors == null || errors.isEmpty()) return null; Iterator<SQLException> iter = errors.iterator(); SQLException root = iter.next(); SQLException last = root; while (iter.hasNext()) { SQLException current = iter.next(); last.setNextException(current); last = current; } return root; } /** * ?? */ public static String decrypt(String pass) { TripleDES t = new TripleDES(); String text = t.decipher2(getEncryptKey(), pass); return text; } /** * ?? */ public static String ecrypt(String pass) throws IOException { TripleDES t = new TripleDES(); String text = t.cipher2(getEncryptKey(), pass); return text; } /** * ?DataSource? * * @param ds */ public static void processDataSourceOfEnCrypted(DataSourceInfo ds) { boolean flag = JefConfiguration.getBoolean(DbCfg.DB_PASSWORD_ENCRYPTED, false); if (!flag) { return; } String old = ds.getPassword(); if (old != null && old.matches("[a-fA-F0-9]{16,}")) { ds.setPassword(decrypt(old)); } } /** * ?select?? * * @param sql * @return * @throws ParseException */ @SuppressWarnings("unchecked") public static List<SelectItem> parseSelectItems(String sql) throws ParseException { JpqlParser parser = new JpqlParser(new StringReader(sql)); return parser.SelectItemsList(); } public static ColumnDefinition parseColumnDef(String def) { String sql = StringUtils.concat("create table A (B ", def, ")"); StSqlParser parser = new StSqlParser(new StringReader(sql)); try { CreateTable ct = parser.CreateTable(); return ct.getColumnDefinitions().get(0); } catch (ParseException e) { throw new IllegalArgumentException("Parse sql error:" + sql, e); } } /** * ?select? * * @param sql * @return * @throws ParseException */ public static Select parseSelect(String sql) throws ParseException { JpqlParser parser = new JpqlParser(new StringReader(sql)); return parser.Select(); } /** * ?Select?(SQL) * * @param sql * @return * @throws ParseException */ public static Select parseNativeSelect(String sql) throws ParseException { StSqlParser parser = new StSqlParser(new StringReader(sql)); return parser.Select(); } /** * ?? * * @param sql * @return * @throws ParseException */ public static Expression parseExpression(String sql) throws ParseException { JpqlParser parser = new JpqlParser(new StringReader(sql)); return parser.SimpleExpression(); } /** * ?OrderBy * * @param sql * @return * @throws ParseException */ public static OrderBy parseOrderBy(String sql) { StSqlParser parser = new StSqlParser(new StringReader("ORDER BY " + sql)); try { return parser.OrderByElements(); } catch (ParseException e) { throw new PersistenceException(sql, e); } } /** * ?? * * @param sql * @return * @throws ParseException */ public static Expression parseBinaryExpression(String sql) throws ParseException { JpqlParser parser = new JpqlParser(new StringReader(sql)); return parser.Expression(); } /** * ?? * * @param sql * @return * @throws ParseException */ public static jef.database.jsqlparser.visitor.Statement parseStatement(String sql) throws ParseException { JpqlParser parser = new JpqlParser(new StringReader(sql)); try { return parser.Statement(); } catch (ParseException e) { LogUtil.error("ErrorSQL:" + sql); throw e; } catch (TokenMgrError e) { LogUtil.error("ErrorSQL:" + sql); throw e; } } /** * ???? * * @param <T> * @param queryObj * @return */ @SuppressWarnings("unchecked") public static <T extends IQueryableEntity> JoinElement toReferenceJoinQuery(Query<T> queryObj, List<Reference> excludeRef) { // ?? Map<Reference, List<AbstractRefField>> map = queryObj.isCascadeViaOuterJoin() ? DbUtils.getMergeAsOuterJoinRef(queryObj) : Collections.EMPTY_MAP; Query<?>[] otherQuery = queryObj.getOtherQueryProvider(); if (otherQuery.length == 0 && map.isEmpty()) { return queryObj; } // AbstractJoinImpl j = DbUtils.getJoin(queryObj, map, ArrayUtils.asList(otherQuery), excludeRef); if (j != null) { j.setFetchSize(queryObj.getFetchSize()); j.setMaxResult(queryObj.getMaxResult()); j.setQueryTimeout(queryObj.getQueryTimeout()); if (queryObj.getSelectItems() != null) { List<QueryAlias> qs = j.allElements(); for (int i = 0; i < qs.size(); i++) { qs.get(i).setAlias("T" + (i + 1)); } SelectsImpl select = new jef.database.query.SelectsImpl(qs); select.merge((AbstractEntityMappingProvider) queryObj.getSelectItems()); j.setSelectItems(select); } // TODO cacheable, Transformer, // attributeQuery???????? j.setResultTransformer(queryObj.getResultTransformer()); j.setCacheable(queryObj.isCacheable()); // FilterCondition? if (queryObj.getFilterCondition() != null) { for (QueryAlias qa : j.allElements()) { if (qa.getStaticRef() != null) { List<Condition> con = queryObj.getFilterCondition().get(qa.getStaticRef()); if (con != null) { j.addRefConditions(qa.getQuery(), con); } } } } return j; } else { return queryObj; } } /** * ?????<br> * you_are_boy -> YouAreBoy * * @param name * ?? * @param capitalize * ??? * @return ???? */ public static String underlineToUpper(String name, boolean capitalize) { char[] r = new char[name.length()]; int n = 0; boolean nextUpper = capitalize; for (char c : name.toCharArray()) { if (c == '_') { nextUpper = true; } else { if (nextUpper) { r[n] = Character.toUpperCase(c); nextUpper = false; } else { r[n] = Character.toLowerCase(c); } n++; } } return new String(r, 0, n); } /** * ??????? : iLoveYou -> i_love_you * * @param name * ??? * @return ???? */ public static String upperToUnderline(String name) { if (name == null) return null; boolean skipUpper = true; StringBuilder sb = new StringBuilder(); char[] chars = name.toCharArray(); sb.append(chars[0]); for (int i = 1; i < chars.length; i++) { if (CharUtils.isUpperAlpha(chars[i])) { if (!skipUpper) { sb.append('_').append(chars[i]); skipUpper = true; } else { if (i + 2 < chars.length && CharUtils.isLowerAlpha(chars[i + 1])) { sb.append('_').append(chars[i]); } else { sb.append(chars[i]); } } } else { sb.append(chars[i]); skipUpper = false; } } return sb.toString().toUpperCase(); } /** * * * @param data * * @param pk * ?Map? */ public static void setPrimaryKeyValue(IQueryableEntity data, Object pk) throws PersistenceException { List<ColumnMapping> fields = MetaHolder.getMeta(data).getPKFields(); if (fields.isEmpty()) return; Assert.notNull(pk); // if (pk instanceof Map) { // Map<String, Object> pkMap = (Map<String, Object>) pk; // BeanWrapper wrapper = BeanWrapper.wrap(data, BeanWrapper.FAST); // for (Field f : fields) { // if (wrapper.isWritableProperty(f.name())) { // wrapper.setPropertyValue(f.name(), pkMap.get(f.name())); // } // } // } else if (pk.getClass().isArray()) { int length = Array.getLength(pk); int n = 0; Assert.isTrue(length == fields.size()); for (ColumnMapping f : fields) { f.getFieldAccessor().set(data, Array.get(pk, n++)); } } else { if (fields.size() != 1) { throw new PersistenceException("No Proper PK fields!"); } fields.get(0).getFieldAccessor().set(data, pk); } } /** * ?? */ public static Map<String, Object> getPrimaryKeyValueMap(IQueryableEntity data) { ITableMetadata meta = MetaHolder.getMeta(data); int len = meta.getPKFields().size(); if (len == 0) return null; Map<String, Object> keyValMap = new HashMap<String, Object>(); for (int i = 0; i < len; i++) { ColumnMapping field = meta.getPKFields().get(i); if (!isValidPKValue(data, meta, field)) { return null; } keyValMap.put(field.fieldName(), field.getFieldAccessor().get(data)); } return keyValMap; } /** * ?? */ public static List<Object> getPrimaryKeyValue(IQueryableEntity data) { ITableMetadata meta = MetaHolder.getMeta(data); if (meta.getPKFields().isEmpty()) return null; int len = meta.getPKFields().size(); Object[] result = new Object[len]; for (int i = 0; i < len; i++) { ColumnMapping field = meta.getPKFields().get(i); if (!isValidPKValue(data, meta, field)) { return null; } result[i] = field.getFieldAccessor().get(data); } return Arrays.asList(result); } // ?????? public static List<Serializable> getPKValueSafe(IQueryableEntity data) { ITableMetadata meta = MetaHolder.getMeta(data); if (meta.getPKFields().isEmpty()) return null; int len = meta.getPKFields().size(); Serializable[] result = new Serializable[len]; for (int i = 0; i < len; i++) { ColumnMapping field = meta.getPKFields().get(i); result[i] = (Serializable) field.getFieldAccessor().get(data); } return Arrays.asList(result); } /** * field?????? * * @param field * * @param feature * ? * @param tableAlias * ?? * @return ?SQL?? * @deprecated use * {@linkplain #toColumnName(ColumnMapping, DatabaseDialect, String)} * instead */ public static String toColumnName(Field field, DatabaseDialect feature, String tableAlias) { if (field instanceof MetadataContainer) { ITableMetadata meta = ((MetadataContainer) field).getMeta(); return getColumnName(meta, field, tableAlias, feature); } ITableMetadata meta = getTableMeta(field); if (field instanceof JpqlExpression) { return ((JpqlExpression) field).toSqlAndBindAttribs(null, feature); } else { return getColumnName(meta, field, tableAlias, feature); } } /** * ?, * * @param column * * @param profile * ? * @param tableAlias * ?? * @return SQL?? */ public static String toColumnName(ColumnMapping column, DatabaseDialect profile, String alias) { if (alias != null) { StringBuilder sb = new StringBuilder(); sb.append(alias).append('.').append(column.getColumnName(profile, true)); return sb.toString(); } else { return column.getColumnName(profile, true); } } /** * ?field??? * * @param field * field * @param alias * ??? * @param profile * ?? * @return ??? * * @deprecated ? */ public static String getColumnName(ITableMetadata meta, Field fld, String alias, DatabaseDialect profile) { if (alias == null) { return meta.getColumnName(fld, profile, true); } else { if (fld instanceof JpqlExpression) { throw new UnsupportedOperationException(); } else { StringBuilder sb = new StringBuilder(); sb.append(alias).append('.').append(meta.getColumnName(fld, profile, true)); return sb.toString(); } } } /* * ???????? * * @param d * * @param map ??? * * @param queryProvider : ?? * * @return */ protected static AbstractJoinImpl getJoin(Query<?> d, Map<Reference, List<AbstractRefField>> map, List<Query<?>> queryProvider, List<Reference> exclude) { AbstractJoinImpl join = null; // ???????? for (Reference r : map.keySet()) { if (exclude != null && exclude.contains(r)) continue; Query<?> tQuery = null; for (Query<?> t : queryProvider) { if (t.getInstance().getClass() == r.getTargetType().getThisType()) { queryProvider.remove(t); tQuery = t; break; } } if (join == null) { join = JoinUtil.create(d, r, tQuery); Assert.notNull(join, "Invalid Reference:" + r.toString()); } else { join = JoinUtil.create(join, r, tQuery); Assert.notNull(join, "Invalid Reference:" + r.toString()); } } // REF???????Join List<QueryAlias> qs = join == null ? Arrays.asList(new QueryAlias(null, d)) : join.allElements(); AbstractEntityMappingProvider tmpContext = new SqlContext(-1, qs, null); for (Condition c : d.getConditions()) { checkIfThereIsExQueryInRefField(c.getField(), tmpContext, queryProvider); } for (OrderField c : d.getOrderBy()) { checkIfThereIsExQueryInRefField(c.getField(), tmpContext, queryProvider); } // ??Query?? while (queryProvider.size() > 0) { int left = queryProvider.size(); for (Iterator<Query<?>> iter = queryProvider.iterator(); iter.hasNext();) { Query<?> tq = iter.next(); AbstractJoinImpl ng = JoinUtil.create(join == null ? d : join, tq, null, null, false); if (ng != null) { iter.remove(); join = ng; } } if (left == queryProvider.size()) {// reverse look for... for (Iterator<Query<?>> iter = queryProvider.iterator(); iter.hasNext();) { Query<?> tq = iter.next(); AbstractJoinImpl ng = JoinUtil.create(join == null ? d : join, tq, null, null, true); if (ng != null) { iter.remove(); join = ng; } } } if (left == queryProvider.size()) {// ??? LogUtil.error("There 's still " + queryProvider.size() + " query not added into join."); break; } } if (join != null) join.fillAttribute((Query<?>) d); return join; } /* * field(fieldRefField) */ private static void checkIfThereIsExQueryInRefField(Field field, AbstractEntityMappingProvider tmpContext, List<Query<?>> qt) { // RefField???refFieldQuery if (field instanceof RefField) { rebindRefField((RefField) field, tmpContext, qt); } else if (field instanceof IConditionField) { IConditionField condf = (IConditionField) field; processConditionField(condf, tmpContext, qt); } } // ?REFField() private static void rebindRefField(RefField ref, AbstractEntityMappingProvider tmpContext, List<Query<?>> qt) { if (!ref.isBindOn(tmpContext)) { Query<?> refQuery = ref.getInstanceQuery(null); for (Query<?> extQuery : qt) { if (refQuery == extQuery) { return; } else if (refQuery.getType() == extQuery.getType() && refQuery.getConditions().equals(extQuery.getConditions())) { // ref.rebind(extQuery,null); return; } } qt.add(refQuery); } } // ?REFField() private static void processConditionField(IConditionField container, AbstractEntityMappingProvider tmpContext, List<Query<?>> qt) { for (Condition c : container.getConditions()) { Field field = c.getField(); if (field instanceof IConditionField) { processConditionField((IConditionField) field, tmpContext, qt); } else if (field instanceof RefField) { rebindRefField((RefField) field, tmpContext, qt); } } } /** * ???? * * @param subs * @param container * @return * @throws SQLException */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected static Object toProperContainerType(Collection<? extends IQueryableEntity> subs, Class<?> container, Class<?> bean, AbstractRefField config) throws SQLException { if (container.isAssignableFrom(subs.getClass())) { return subs; } if (container == Set.class) { HashSet set = new HashSet(); set.addAll(subs); return set; } else if (container == List.class) { ArrayList list = new ArrayList(); list.addAll(subs); return list; } else if (container == Array.class) { return subs.toArray(); } else if (container == Map.class) { Cascade cascade = config.getCascadeInfo(); if (cascade == null) { throw new SQLException("@Cascade annotation is required for Map mapping " + config.toString()); } Map map = new HashMap(); String key = cascade.keyOfMap(); BeanAccessor ba = FastBeanWrapperImpl.getAccessorFor(bean); if (StringUtils.isEmpty(cascade.valueOfMap())) { for (IQueryableEntity e : subs) { map.put(ba.getProperty(e, key), e); } } else { String vField = cascade.valueOfMap(); for (IQueryableEntity e : subs) { map.put(ba.getProperty(e, key), ba.getProperty(e, vField)); } } return map; } throw new SQLException("the type " + container.getName() + " is not supported as a collection container."); } /** * * * @param data * @return */ protected static Map<Reference, List<AbstractRefField>> getMergeAsOuterJoinRef(Query<?> q) { Map<Reference, List<AbstractRefField>> result = new HashMap<Reference, List<AbstractRefField>>(5); // ? for (Map.Entry<Reference, List<AbstractRefField>> entry : q.getMeta().getRefFieldsByRef().entrySet()) { Reference key = entry.getKey(); if (key.getType().isToOne()) { List<AbstractRefField> value = entry.getValue(); AbstractRefField first = value.get(0); if (first.getFetch() == FetchType.LAZY) { continue; } result.put(key, value); } } // ??? if (q.getFilterCondition() != null) { for (Reference ref : q.getFilterCondition().keySet()) { if (ref.getType().isToOne() && ref.getJoinType() != JoinType.LEFT) { result.remove(ref); } } } return result; } /** * Ref * * @param data * * @param excludeReference * ??null? * @return */ protected static Map<Reference, List<AbstractRefField>> getLazyLoadRef(ITableMetadata data, Collection<Reference> excludeReference) { // ==null???,? // ??? if (excludeReference == null) { Map<Reference, List<AbstractRefField>> result = new HashMap<Reference, List<AbstractRefField>>(5); for (Map.Entry<Reference, List<AbstractRefField>> entry : data.getRefFieldsByRef().entrySet()) { Reference key = entry.getKey(); ReferenceType type = key.getType(); List<AbstractRefField> value = entry.getValue(); if (type.isToOne()) { if (value.get(0).getFetch() == FetchType.LAZY) { result.put(key, value); } } else { result.put(key, value); } } return result; // ???? } else if (excludeReference.isEmpty()) { return data.getRefFieldsByRef(); // !!???,??ref } else { Map<Reference, List<AbstractRefField>> result = new HashMap<Reference, List<AbstractRefField>>( data.getRefFieldsByRef()); for (Reference ref : excludeReference) { result.remove(ref); } return result; } } /** * class * * @param field * @return */ public static AbstractMetadata getTableMeta(Field field) { Assert.notNull(field); if (field instanceof MetadataContainer) { return (AbstractMetadata) ((MetadataContainer) field).getMeta(); } if (field instanceof Enum) { // FIXME ?? Class<?> c = field.getClass().getDeclaringClass(); Assert.isTrue(IQueryableEntity.class.isAssignableFrom(c), field + " is not a defined in a IQueryableEntity's meta-model."); return MetaHolder.getMeta(c.asSubclass(IQueryableEntity.class)); } else { throw new IllegalArgumentException( "method 'getTableMeta' doesn't support field type of " + field.getClass()); } } /** * * * @param field * * @return ?? */ public static ColumnMapping toColumnMapping(Field field) { if (field instanceof ColumnMapping) { return (ColumnMapping) field; } else if (field instanceof MetadataContainer) { return ((MetadataContainer) field).getMeta().getColumnDef(field); } else if (field instanceof Enum) { Class<?> c = field.getClass().getDeclaringClass(); Assert.isTrue(IQueryableEntity.class.isAssignableFrom(c), field + " is not a defined in a IQueryableEntity's meta-model."); ITableMetadata meta = MetaHolder.getMeta(c); return meta.getColumnDef(field); } throw new IllegalArgumentException( "method 'getTableMeta' doesn't support field type of " + field.getClass()); } /** * ?? * * @param bean * @param rs * @param query * @return */ protected static boolean appendRefCondition(BeanWrapper bean, JoinPath rs, Query<?> query, List<Condition> filters) { query.clearQuery(); boolean hasValue = false; for (JoinKey r : rs.getJoinKeys()) { Object value = bean.getPropertyValue(r.getLeft().name()); query.addCondition(r.getRightAsField(), value); if (value != null) hasValue = true; } // ??hasValue for (JoinKey condition : rs.getJoinExpression()) { Field f = condition.getLeft(); if (f == null) { continue; } if (f instanceof SqlExpression) { query.addCondition(condition); continue; } if (f instanceof JpqlExpression) { query.addCondition(condition); continue; } ITableMetadata meta = DbUtils.getTableMeta(f); if (meta == query.getMeta()) { query.addCondition(condition); } } if (filters != null) { Query<?> bq = query; bq.getConditions().addAll(filters); } return hasValue; } /** * * * @param obj * @param query * @param isUpdate * isUpdatetrue?updateMap * ??whereset? * @param force * @return */ protected static void fillConditionFromField(IQueryableEntity obj, Query<?> query, UpdateContext update, boolean force) { Assert.isTrue(query.getConditions().isEmpty()); ITableMetadata meta = query.getMeta(); boolean isUpdate = update != null; if (fillPKConditions(obj, meta, query, isUpdate, force)) { if (isUpdate) update.setIsPkQuery(true); return; } populateExampleConditions(obj); } /* * (nojava doc) */ private static boolean isValidPKValue(IQueryableEntity obj, ITableMetadata meta, ColumnMapping field) { Class<?> type = field.getFieldAccessor().getType(); Object value = field.getFieldAccessor().get(obj); if (field.isUnsavedValueDeclared()) { return !field.isUnsavedValue(value); } else if (type.isPrimitive()) { if (field.isUnsavedValue(value)) { if (!obj.isUsed(field.field())) return false; } return true; } else { return value != null; } } /** * ?? ? 1???? 2??? * * @param value * @param field * @param isUsed * @return true */ public static boolean isInvalidValue(Object value, ColumnMapping field, boolean isUsed) { if (field.isUnsavedValueDeclared()) { return field.isUnsavedValue(value); } // ????? // primitive if (!isUsed && field.getFieldAccessor().getType().isPrimitive()) { return field.isUnsavedValue(value); } return false; } /* * @param obj * * @param meta ? * * @param wrapper * * @param query * * @param removePkUpdate * * @param force * * @return */ protected static boolean fillPKConditions(IQueryableEntity obj, ITableMetadata meta, Query<?> query, boolean isUpdate, boolean force) { if (meta.getPKFields().isEmpty()) return false; if (!force) { for (ColumnMapping field : meta.getPKFields()) { if (!isValidPKValue(obj, meta, field)) return false; } } Map<Field, Object> map = obj.getUpdateValueMap(); for (ColumnMapping mapping : meta.getPKFields()) { Object value = mapping.getFieldAccessor().get(obj); Field field = mapping.field(); query.addCondition(field, value); if (isUpdate && map.containsKey(field)) {// Object v = map.get(field); if (Objects.equal(value, v)) { map.remove(field); } } } return true; } /** * ?update'' <br> * ??updateMap * * @param <T> * @param prepareObj */ public static <T extends IQueryableEntity> void fillUpdateMap(T... obj) { if (obj == null || obj.length == 0) return; ITableMetadata m = MetaHolder.getMeta(obj[0]); for (T o : obj) { BeanWrapper bean = BeanWrapper.wrap(o); for (ColumnMapping mType : m.getColumns()) { if (mType.isPk()) { continue; } Field field = mType.field(); o.prepareUpdate(field, bean.getPropertyValue(field.name()), true); } } } /** * ??Example? * * @param obj * @return */ @SuppressWarnings("unchecked") public static <T extends IQueryableEntity> Query<T> populateExampleConditions(T obj, String... properties) { Query<T> query = (Query<T>) obj.getQuery(); ITableMetadata meta = query.getMeta(); BeanWrapper bw = BeanWrapper.wrap(obj, BeanWrapper.FAST); if (properties.length == 0) { for (ColumnMapping mType : meta.getColumns()) { Field field = mType.field(); if (obj.isUsed(field)) { Object value = bw.getPropertyValue(field.name()); query.addCondition(field, value); } } } else { for (String s : properties) { Field field = meta.getField(s); if (field == null) { throw new IllegalArgumentException("field [" + s + "] not found in object " + meta.getName()); } Object value = bw.getPropertyValue(field.name()); query.addCondition(field, value); } } return query; } /** * ?? * * @param queryObj * @return */ protected static EntityMappingProvider getMappingProvider(ConditionQuery queryObj) { if (queryObj instanceof JoinElement) { return ((JoinElement) queryObj).getSelectItems(); } return null; } /** * ?????? * * @param name * @param needTranslate * @return */ public static PartitionResult[] toTableNames(IQueryableEntity obj, String customName, Query<?> q, PartitionSupport processor) { AbstractMetadata meta = q == null ? MetaHolder.getMeta(obj) : (AbstractMetadata) q.getMeta(); if (StringUtils.isNotEmpty(customName)) return new PartitionResult[] { new PartitionResult(customName).setDatabase(meta.getBindDsName()) }; PartitionResult[] result = partitionUtil.toTableNames(meta, obj, q, processor, ORMConfig.getInstance().isFilterAbsentTables()); // if(ORMConfig.getInstance().isDebugMode()){ // LogUtil.show("Partitions:"+Arrays.toString(result)); // } return result; } /** * ???? * * * @param meta * ??? * @param processor * @param operateType * ???0 1 ?? 2 + 3 ??? 4 * ? * * * @return */ public static PartitionResult[] toTableNames(ITableMetadata meta, PartitionSupport processor, int operateType) { Assert.notNull(meta); // long start=System.nanoTime(); // try{ return partitionUtil.toTableNames((AbstractMetadata) meta, processor, operateType); // }finally{ // System.out.println((System.nanoTime()-start)/1000+"us"); // } } /** * ??????? * * @param obj * @param customName * @param q * @param profile * @return */ public static PartitionResult toTableName(IQueryableEntity obj, String customName, Query<?> q, PartitionSupport profile) { AbstractMetadata meta = obj == null ? (AbstractMetadata) q.getMeta() : MetaHolder.getMeta(obj); if (StringUtils.isNotEmpty(customName)) return new PartitionResult(customName).setDatabase(meta.getBindDsName()); PartitionResult result = partitionUtil.toTableName(meta, obj, q, profile); Assert.notNull(result); return result; } // /** // * dbkey????? // * ?rac?? // * @param dbkey,anotherDbKeytrue // * @return // */ // public static boolean isSameDb(String dbkey,String anotherDbKey){ // if(StringUtils.isEmpty(dbkey)&&StringUtils.isEmpty(anotherDbKey)){ // return true; // } // if(StringUtils.isEmpty(dbkey)) // return false; // if(dbkey.equalsIgnoreCase(anotherDbKey)) // return true; // String racId = getRacId(dbkey); // String anotherRacId = getRacId(anotherDbKey); // // return // racId!=null&&!String.valueOf(NO_RAC_ID).equals(racId)&&racId.equalsIgnoreCase(anotherRacId); // } /** * ? * * @param rs */ public static void close(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } } /** * Statement * * @param st */ public static void close(Statement st) { try { if (st != null) st.close(); } catch (SQLException e) { } } /** * RuntimeException * * @param e * @return */ public static PersistenceException toRuntimeException(SQLException e) { String s = e.getSQLState(); if (e instanceof SQLIntegrityConstraintViolationException) { return new EntityExistsException(e); } else if (e instanceof SQLTimeoutException) { return new QueryTimeoutException(s, e); } return new PersistenceException(s, e); } /** * Runtime * * @param e * @return */ public static RuntimeException toRuntimeException(Throwable e) { while (true) { if (e instanceof RuntimeException) { return (RuntimeException) e; } if (e instanceof InvocationTargetException) { e = e.getCause(); continue; } if (e instanceof Error) { throw (Error) e; } if (e instanceof SQLException) { return toRuntimeException((SQLException) e); } return new IllegalStateException(e); } } private static final String DEFAULT_SEQUENCE_PATTERN = "S_%s"; private static final int TABLE_NAME_MAX_LENGTH = 26; public static String calcSeqNameByTable(String schema, String tableName, String columnName) { String pattern = JefConfiguration.get(DbCfg.SEQUENCE_NAME_PATTERN); if (StringUtils.isBlank(pattern)) pattern = DEFAULT_SEQUENCE_PATTERN; String tblName = tableName; if (tblName.length() > TABLE_NAME_MAX_LENGTH) { tblName = tblName.substring(0, TABLE_NAME_MAX_LENGTH); } if (schema == null) { return StringUtils.upperCase(String.format(pattern, tblName)); } else { String name = String.format(pattern, tblName); return new StringBuilder(schema.length() + name.length() + 1).append(schema).append('.').append(name) .toString().toUpperCase(); } } // TODO Oracle RAC?URL // public static String getSimpleUrl(String url) { // if (url.toLowerCase().indexOf("service_name") > -1) { // StringBuilder sb=new StringBuilder(); // StringTokenizer st=new StringTokenizer(url,"()"); // while(st.hasMoreTokens()){ // String str=st.nextToken(); // String x=str.toUpperCase(); // if(x.startsWith("SERVICE_NAME") || x.startsWith("HOST")){ // sb.append('(').append(str).append(')'); // } // } // url = sb.toString(); // } // return url; // } /** * JDBC URLdatasource??? * * @param url * @param user * @param password * @return */ public static SimpleDataSource createSimpleDataSource(String url, String user, String password) { SimpleDataSource s = new SimpleDataSource(); s.setUsername(user); s.setUrl(url); s.setPassword(password); return s; } /** * * * @param subclass * @param superclass * @return */ public static Type[] getTypeParameters(Class<?> subclass, Class<?> superclass) { if (superclass == null) {// ? if (subclass.getSuperclass() == Object.class && subclass.getInterfaces().length > 0) { superclass = subclass.getInterfaces()[0]; } else { superclass = subclass.getSuperclass(); } } Type type = GenericUtils.getSuperType(null, subclass, superclass); if (type instanceof ParameterizedType) { return ((ParameterizedType) type).getActualTypeArguments(); } throw new RuntimeException("Can not get the generic param type for class:" + subclass.getName()); } /** * Map * * @param <T> * @param changedObj * @param oldObj * @throws SQLException * @return the object who is able to update. */ public static <T extends IQueryableEntity> T compareToUpdateMap(T changedObj, T oldObj) { // Assert.isTrue(Objects.equal(DbUtils.getPrimaryKeyValue(changedObj), // DbUtils.getPKValueSafe(oldObj)), // "For consistence, the two parameter must hava equally primary // keys."); ITableMetadata m = MetaHolder.getMeta(oldObj); boolean safeMerge = ORMConfig.getInstance().isSafeMerge(); for (ColumnMapping mType : m.getColumns()) { if (mType.isPk()) continue; Field field = mType.field(); Object value = mType.getFieldAccessor().get(changedObj); boolean used = changedObj.isUsed(field); if (mType.isGenerated() && !used) { continue; } // ? if (safeMerge && DbUtils.isInvalidValue(value, mType, used)) { continue; } Object oldValue = mType.getFieldAccessor().get(oldObj); if (!ObjectUtils.equals(value, oldValue)) { oldObj.prepareUpdate(field, value); } } return oldObj; } }