001package fr.ifremer.adagio.synchro.meta; 002 003/* 004 * #%L 005 * Tutti :: Persistence API 006 * $Id: TuttiEntities.java 1578 2014-02-07 15:31:18Z tchemit $ 007 * $HeadURL: http://svn.forge.codelutin.com/svn/tutti/trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/entities/TuttiEntities.java $ 008 * %% 009 * Copyright (C) 2012 Ifremer 010 * %% 011 * This program is free software: you can redistribute it and/or modify 012 * it under the terms of the GNU Affero General Public License as published by 013 * the Free Software Foundation, either version 3 of the License, or 014 * (at your option) any later version. 015 * 016 * This program is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 019 * GNU General Public License for more details. 020 * 021 * You should have received a copy of the GNU Affero General Public License 022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 023 * #L% 024 */ 025 026import java.sql.Types; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import org.apache.commons.collections.CollectionUtils; 032 033import com.google.common.base.Preconditions; 034import com.google.common.base.Predicate; 035import com.google.common.collect.Lists; 036import com.google.common.collect.Sets; 037 038import fr.ifremer.adagio.synchro.SynchroTechnicalException; 039 040/** 041 * Useful method around DAO and entities. 042 * 043 * @author Benoit Lavenier <benoit.lavenier@e-is.pro> 044 * @since 3.5.4 045 */ 046public class SynchroMetadataUtils { 047 048 public static final List<String> ORACLE_EXCLUDE_TABLE_PATTERNS = Lists.newArrayList( 049 "BIN%", // Trash Oracle 050 "MDR%" // Table metadata spatial 051 ); 052 053 protected SynchroMetadataUtils() { 054 // helper class does not instantiate 055 } 056 057 public static Predicate<String> newAllTablesOraclePredicate() { 058 return newTablesOraclePredicate(null, null); 059 } 060 061 public static Predicate<String> newTablesOraclePredicate(Set<String> excludes, final Set<String> includes) { 062 Set<String> excludesPatterns = Sets.newHashSet(ORACLE_EXCLUDE_TABLE_PATTERNS); 063 064 if (CollectionUtils.isNotEmpty(excludes)) { 065 excludesPatterns.addAll(excludes); 066 } 067 068 return newTablePredicate(excludesPatterns, includes); 069 } 070 071 public static Predicate<String> newTablePredicate(final Set<String> excludes, final Set<String> includes) { 072 // If no filter 073 if (CollectionUtils.isEmpty(excludes) && CollectionUtils.isEmpty(includes)) { 074 return null; 075 } 076 077 return new Predicate<String>() { 078 public boolean apply(String tableName) { 079 080 if (CollectionUtils.isNotEmpty(excludes)) { 081 for (String excludePattern : excludes) { 082 if (tableName.matches(excludePattern.replaceAll("%", ".*"))) { 083 return false; 084 } 085 } 086 } 087 if (CollectionUtils.isEmpty(includes)) { 088 return true; 089 } 090 for (String includePattern : includes) { 091 if (tableName.matches(includePattern.replaceAll("%", ".*"))) { 092 return true; 093 } 094 } 095 return false; 096 } 097 }; 098 } 099 100 public static Predicate<SynchroColumnMetadata> newExcludeColumnPredicate(final Map<String, Set<String>> excludeColumnNamesMap) { 101 Preconditions.checkNotNull(excludeColumnNamesMap); 102 Preconditions.checkArgument(!excludeColumnNamesMap.isEmpty()); 103 104 return new Predicate<SynchroColumnMetadata>() { 105 public boolean apply(SynchroColumnMetadata input) { 106 Set<String> excludeColumnNames = excludeColumnNamesMap.get(input.getTableName()); 107 return CollectionUtils.isEmpty(excludeColumnNames) || !excludeColumnNames.contains(input.getName().toLowerCase()); 108 } 109 }; 110 } 111 112 /** 113 * Check if types are compatible, and return a DataRetrievalFailureException if not compatible. 114 * 115 * @param tableName 116 * @param internalColumn 117 * @param externalColumn 118 */ 119 public static void checkType(String tableName, SynchroColumnMetadata internalColumn, SynchroColumnMetadata externalColumn) { 120 121 // If numeric 122 if (isNumericType(internalColumn) && isNumericType(externalColumn)) { 123 int internalColumnSize = internalColumn.getColumnSize(); 124 int externalColumnSize = externalColumn.getColumnSize(); 125 if (internalColumnSize > 0 && externalColumnSize > 0 && internalColumnSize < externalColumnSize) { 126 throw new SynchroTechnicalException(String.format("Incompatible column type of table / column: %s / %s", tableName, 127 internalColumn.getName())); 128 } 129 int internalDecimalDigits = internalColumn.getDecimalDigits(); 130 int externalDecimalDigits = externalColumn.getDecimalDigits(); 131 if (internalDecimalDigits > 0 && externalDecimalDigits > 0 && internalDecimalDigits < externalDecimalDigits) { 132 throw new SynchroTechnicalException(String.format("Incompatible column type of table / column: %s / %s", tableName, 133 internalColumn.getName())); 134 } 135 } 136 137 // If Date 138 else if (isDateType(internalColumn) && isDateType(externalColumn)) { 139 // OK 140 } 141 142 // If Boolean 143 else if (isBooleanType(internalColumn) && isBooleanType(externalColumn)) { 144 // OK 145 } 146 147 // Else : compare type code and name 148 else { 149 String internalColumnTypeName = internalColumn.getTypeName(); 150 String externalColumnTypeName = externalColumn.getTypeName(); 151 int internalColumnTypeCode = internalColumn.getTypeCode(); 152 int externalColumnTypeCode = externalColumn.getTypeCode(); 153 154 if (internalColumnTypeCode != externalColumnTypeCode && internalColumnTypeName.equals(externalColumnTypeName) == false) { 155 throw new SynchroTechnicalException(String.format("Incompatible column type of table / column: %s / %s", tableName, 156 internalColumn.getName())); 157 } 158 } 159 } 160 161 protected static boolean isNumericType(SynchroColumnMetadata column) { 162 int typeCode = column.getTypeCode(); 163 if (typeCode == Types.BIGINT || typeCode == Types.INTEGER || typeCode == Types.NUMERIC 164 || typeCode == Types.DECIMAL || typeCode == Types.FLOAT || typeCode == Types.REAL 165 || typeCode == Types.SMALLINT || typeCode == Types.TINYINT || typeCode == Types.DOUBLE) { 166 return true; 167 } 168 169 String columnTypeName = column.getTypeName(); 170 return columnTypeName.equals("NUMBER") || columnTypeName.equals("INTEGER") || columnTypeName.equals("SMALLINT"); 171 } 172 173 protected static boolean isDateType(SynchroColumnMetadata column) { 174 String columnTypeName = column.getTypeName(); 175 return columnTypeName.equals("TIMESTAMP") || columnTypeName.equals("DATE"); 176 } 177 178 protected static boolean isBooleanType(SynchroColumnMetadata column) { 179 String columnTypeName = column.getTypeName(); 180 int columnSize = column.getColumnSize(); 181 return columnTypeName.equals("BOOLEAN") || 182 (columnTypeName.equals("NUMBER") && columnSize == 1); 183 } 184 185}