1 package fr.ifremer.quadrige2.synchro.intercept.system;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import com.google.common.base.Joiner;
27 import com.google.common.collect.ArrayListMultimap;
28 import com.google.common.collect.ImmutableList;
29 import com.google.common.collect.Multimap;
30 import com.google.common.collect.MultimapBuilder;
31 import com.google.common.eventbus.Subscribe;
32 import fr.ifremer.common.synchro.intercept.SynchroInterceptorBase;
33 import fr.ifremer.common.synchro.meta.SynchroJoinMetadata;
34 import fr.ifremer.common.synchro.meta.SynchroMetadataUtils;
35 import fr.ifremer.common.synchro.meta.SynchroTableMetadata;
36 import fr.ifremer.common.synchro.meta.event.CreateQueryEvent;
37 import fr.ifremer.common.synchro.meta.event.LoadJoinEvent;
38 import fr.ifremer.common.synchro.meta.event.LoadTableEvent;
39 import fr.ifremer.common.synchro.query.SynchroQueryBuilder;
40 import fr.ifremer.common.synchro.query.SynchroQueryName;
41 import fr.ifremer.common.synchro.query.SynchroQueryOperator;
42 import fr.ifremer.common.synchro.service.SynchroDatabaseConfiguration;
43 import fr.ifremer.quadrige2.synchro.intercept.referential.AbstractReferentialInterceptor;
44 import fr.ifremer.quadrige2.synchro.intercept.referential.internal.ImportFromFileFkInterceptor;
45 import fr.ifremer.quadrige2.synchro.meta.DatabaseColumns;
46 import fr.ifremer.quadrige2.synchro.meta.system.RuleSynchroTables;
47 import fr.ifremer.quadrige2.synchro.service.SynchroDirection;
48 import fr.ifremer.quadrige2.synchro.service.referential.ReferentialSynchroDatabaseConfiguration;
49 import org.apache.commons.collections4.CollectionUtils;
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52
53 import java.util.Collection;
54 import java.util.Set;
55
56
57
58
59
60
61
62 public class RuleTableInterceptor extends AbstractReferentialInterceptor {
63
64
65
66 public static final Multimap<String, String> naturalIds;
67
68 protected static final Multimap<String, String> childJoinIncludes;
69
70 protected static final Multimap<String, String> childJoinExcludes;
71 private static final Log log = LogFactory.getLog(RuleTableInterceptor.class);
72
73 static {
74 childJoinIncludes = initChildJoinIncludes();
75 childJoinExcludes = initChildJoinExcludes();
76 naturalIds = initNaturalIds();
77 }
78
79 private String statusWhereClause;
80
81
82
83
84
85
86 public RuleTableInterceptor() {
87 super(RuleSynchroTables.tableNames());
88 }
89
90
91
92
93
94
95
96
97 protected static Multimap<String, String> initChildJoinIncludes() {
98 Multimap<String, String> result = ArrayListMultimap.create();
99
100
101 result.put(RuleSynchroTables.RULE_LIST_RESP_DEP.name(), DatabaseColumns.RULE_LIST_CD.name());
102 result.put(RuleSynchroTables.RULE_LIST_PROG.name(), DatabaseColumns.RULE_LIST_CD.name());
103 result.put(RuleSynchroTables.RULE_LIST_RESP_QUSER.name(), DatabaseColumns.RULE_LIST_CD.name());
104 result.put(RuleSynchroTables.RULE_LIST_CONTROLED_DEP.name(), DatabaseColumns.RULE_LIST_CD.name());
105 result.put(RuleSynchroTables.RULE.name(), DatabaseColumns.RULE_LIST_CD.name());
106 result.put(RuleSynchroTables.RULE_PMFM.name(), DatabaseColumns.RULE_CD.name());
107 result.put(RuleSynchroTables.RULE_PARAMETER.name(), DatabaseColumns.RULE_CD.name());
108 result.put(RuleSynchroTables.RULE_PRECONDITION.name(), DatabaseColumns.RULE_CD.name());
109
110 return result;
111 }
112
113
114
115
116
117
118
119
120 protected static Multimap<String, String> initChildJoinExcludes() {
121 Multimap<String, String> result = ArrayListMultimap.create();
122
123
124
125
126 return result;
127 }
128
129
130
131
132
133
134
135
136 protected static Multimap<String, String> initNaturalIds() {
137
138 Multimap<String, String> result = MultimapBuilder.hashKeys().arrayListValues().build();
139
140
141 result.putAll(RuleSynchroTables.RULE_LIST.name(), ImmutableList.of(
142 DatabaseColumns.RULE_LIST_CD.name()));
143
144 result.putAll(RuleSynchroTables.RULE.name(), ImmutableList.of(
145 DatabaseColumns.RULE_CD.name()));
146
147 return result;
148 }
149
150
151 @Override
152 protected void init(ReferentialSynchroDatabaseConfiguration config) {
153 super.init(config);
154 statusWhereClause = createStatusWhereClause(config);
155 setEnableOnWrite(true);
156 }
157
158
159 @Override
160 public SynchroInterceptorBase clone() {
161 RuleTableInterceptor result = (RuleTableInterceptor) super.clone();
162 result.statusWhereClause = this.statusWhereClause;
163 return result;
164 }
165
166
167
168
169
170
171
172
173
174
175
176 @Subscribe
177 public void handleQuery(CreateQueryEvent e) {
178
179 switch (e.queryName) {
180 case count:
181 case countFromUpdateDate:
182 case select:
183 case selectFromUpdateDate:
184 case selectMaxUpdateDate:
185
186 e.sql = addRestriction(e.source, e.queryName, e.sql);
187
188 default:
189 break;
190 }
191 }
192
193
194
195
196
197
198
199
200
201 @Subscribe
202 public void handleTableLoad(LoadTableEvent e) {
203
204 SynchroTableMetadata table = e.table;
205 SynchroDirection direction = getConfig().getDirection();
206
207 boolean hasStatusFilter = statusWhereClause != null;
208 boolean hasUpdateDateColumn = hasColumns(table, DatabaseColumns.UPDATE_DT.name());
209 boolean hasStatusCdColumn = hasColumns(table, DatabaseColumns.STATUS_CD.name());
210 boolean isRoot = hasUpdateDateColumn && (!hasStatusFilter || hasStatusCdColumn);
211
212
213
214
215
216
217 if (!table.isRoot() && isRoot) {
218 table.setRoot(true);
219 }
220
221
222 String tableName = table.getName();
223 boolean isRootWithoutStatusCd = !hasStatusCdColumn && hasStatusFilter
224 && (tableName.equalsIgnoreCase(RuleSynchroTables.RULE_LIST.name()));
225 if (!table.isRoot() && isRootWithoutStatusCd) {
226 table.setRoot(true);
227 }
228
229
230 if (direction == SynchroDirection.IMPORT_FILE2LOCAL) {
231 Collection<String> columnNames = naturalIds.get(table.getName());
232 if (CollectionUtils.isNotEmpty(columnNames)) {
233 table.addUniqueConstraint("NATURAL_ID_UNIQUE_C", ImmutableList.copyOf(columnNames),
234 SynchroTableMetadata.DuplicateKeyStrategy.REPLACE_AND_REMAP);
235 }
236 }
237 }
238
239
240
241
242
243
244
245
246
247 @Subscribe
248 public void handleJoinLoad(LoadJoinEvent e) {
249 SynchroJoinMetadata join = e.join;
250
251 SynchroTableMetadata fkTable = join.getFkTable();
252 String fkTableName = join.getFkTable().getName().toUpperCase();
253 String pkTableName = join.getPkTable().getName().toUpperCase();
254 String fkColumnName = join.getFkColumn().getName().toUpperCase();
255
256 boolean hasStatusFilter = statusWhereClause != null;
257 boolean fkTableHasUpdateDateColumn = hasColumns(join.getFkTable(), DatabaseColumns.UPDATE_DT.name());
258 boolean fkTableHasStatusCdColumn = hasColumns(join.getFkTable(), DatabaseColumns.STATUS_CD.name());
259 boolean fkTableIsRoot = fkTableHasUpdateDateColumn && (!hasStatusFilter || fkTableHasStatusCdColumn);
260 boolean isNumericColumn = SynchroMetadataUtils.isNumericType(fkTable.getColumnMetadata(fkColumnName));
261 SynchroDirection direction = getConfig().getDirection();
262
263
264 if (join.getFkTable() == join.getPkTable()) {
265 if (log.isDebugEnabled()) {
266 log.debug("Disable join: " + join.toString());
267 }
268 join.setIsValid(false);
269 return;
270 }
271
272
273 if (join.isChild() && fkTableIsRoot) {
274 if (log.isDebugEnabled()) {
275 log.debug("Disable join: " + join.toString());
276 }
277 join.setIsValid(false);
278 return;
279 } else if (join.isChild() && fkTableHasUpdateDateColumn && hasStatusFilter) {
280
281 return;
282 }
283
284
285 if (join.isChild()) {
286
287 Collection<String> columnIncludes = childJoinIncludes.get(fkTableName);
288 boolean explicitlyInclude = CollectionUtils.isNotEmpty(columnIncludes) && columnIncludes.contains(fkColumnName);
289
290
291 Collection<String> columnExcludes = childJoinExcludes.get(fkTableName);
292 boolean explicitlyExclude = CollectionUtils.isNotEmpty(columnExcludes) && columnExcludes.contains(fkColumnName);
293
294 if (!explicitlyInclude || explicitlyExclude) {
295 if (log.isDebugEnabled()) {
296 log.debug("Disable join: " + join.toString());
297 }
298 join.setIsValid(false);
299 }
300 }
301
302
303
304 if (fkTable == e.source) {
305
306
307 if (direction == SynchroDirection.IMPORT_FILE2LOCAL
308 && isNumericColumn
309 && join.getPkTable().isSimpleKey()) {
310 int fkColumnIndex = fkTable.getSelectColumnIndex(fkColumnName);
311
312 ImportFromFileFkInterceptor fkInterceptor = new ImportFromFileFkInterceptor(
313 pkTableName,
314 fkColumnIndex,
315 getConfig());
316
317 if (!fkTable.containsInterceptor(fkInterceptor)) {
318 fkTable.addInterceptor(fkInterceptor);
319 }
320 }
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333 protected String createStatusWhereClause(SynchroDatabaseConfiguration config) {
334
335 Set<String> statusToInclude = getConfig().getStatusCodeIncludes();
336 if (CollectionUtils.isEmpty(statusToInclude)) {
337 return null;
338 }
339
340 return String.format("t.%s IN ('%s')",
341 DatabaseColumns.STATUS_CD,
342 Joiner.on("','").join(statusToInclude));
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358 protected String addRestriction(SynchroTableMetadata table, SynchroQueryName queryName, String sql) {
359 SynchroQueryBuilder queryBuilder = SynchroQueryBuilder.newBuilder(sql);
360
361
362 if (statusWhereClause != null
363 && hasColumns(table, DatabaseColumns.STATUS_CD.name())) {
364 queryBuilder.addWhere(SynchroQueryOperator.AND, statusWhereClause);
365 }
366
367 return queryBuilder.build();
368 }
369 }