1 package fr.ifremer.quadrige3.synchro.intercept.referential;
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.*;
28 import com.google.common.eventbus.Subscribe;
29 import fr.ifremer.common.synchro.intercept.SynchroInterceptorBase;
30 import fr.ifremer.common.synchro.meta.SynchroJoinMetadata;
31 import fr.ifremer.common.synchro.meta.SynchroMetadataUtils;
32 import fr.ifremer.common.synchro.meta.SynchroTableMetadata;
33 import fr.ifremer.common.synchro.meta.event.CreateQueryEvent;
34 import fr.ifremer.common.synchro.meta.event.LoadJoinEvent;
35 import fr.ifremer.common.synchro.meta.event.LoadTableEvent;
36 import fr.ifremer.common.synchro.query.SynchroQueryBuilder;
37 import fr.ifremer.common.synchro.query.SynchroQueryName;
38 import fr.ifremer.common.synchro.query.SynchroQueryOperator;
39 import fr.ifremer.quadrige3.core.dao.referential.StatusCode;
40 import fr.ifremer.quadrige3.synchro.intercept.referential.internal.ImportFromFileFkInterceptor;
41 import fr.ifremer.quadrige3.synchro.intercept.referential.internal.ImportFromFileNumericalPkInterceptor;
42 import fr.ifremer.quadrige3.synchro.meta.DatabaseColumns;
43 import fr.ifremer.quadrige3.synchro.meta.administration.MetaProgramSynchroTables;
44 import fr.ifremer.quadrige3.synchro.meta.referential.ReferentialSynchroTables;
45 import fr.ifremer.quadrige3.synchro.meta.system.ContextAndFilterSynchroTables;
46 import fr.ifremer.quadrige3.synchro.service.SynchroDirection;
47 import fr.ifremer.quadrige3.synchro.service.referential.ReferentialSynchroDatabaseConfiguration;
48 import org.apache.commons.collections4.CollectionUtils;
49 import org.apache.commons.lang3.StringUtils;
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52
53 import java.util.Collection;
54 import java.util.Map;
55 import java.util.Set;
56
57
58
59
60
61
62
63 public class ReferentialTableInterceptor extends AbstractReferentialInterceptor {
64
65 private static final Log log = LogFactory.getLog(ReferentialTableInterceptor.class);
66
67
68 private static final Multimap<String, String> childJoinIncludes;
69
70 private static final Multimap<String, String> childJoinExcludes;
71
72 private static final Multimap<String, String> naturalIds;
73
74 static {
75 childJoinIncludes = initChildJoinIncludes();
76 childJoinExcludes = initChildJoinExcludes();
77 naturalIds = initNaturalIds();
78 }
79
80 private String statusWhereClauseOrNull;
81 private final Map<String, Map<String, Integer>> recursiveColumnsByTable = Maps.newHashMap();
82
83
84
85
86
87
88 public ReferentialTableInterceptor() {
89 super(ReferentialSynchroTables.getImportTablesIncludes());
90 }
91
92
93 @Override
94 protected void init(ReferentialSynchroDatabaseConfiguration config) {
95 statusWhereClauseOrNull = createStatusWhereClauseOrNull(config);
96 }
97
98
99 @Override
100 public SynchroInterceptorBase clone() {
101 ReferentialTableInterceptor result = (ReferentialTableInterceptor) super.clone();
102 result.statusWhereClauseOrNull = this.statusWhereClauseOrNull;
103 return result;
104 }
105
106
107
108
109
110
111
112
113
114 @Subscribe
115 public void handleQuery(CreateQueryEvent e) {
116
117 switch (e.queryName) {
118 case count:
119 case countFromUpdateDate:
120 case select:
121 case selectFromUpdateDate:
122 case selectMaxUpdateDate:
123
124 e.sql = addRestriction(e.source, e.queryName, e.sql);
125
126 default:
127 break;
128 }
129 }
130
131
132
133
134
135
136
137
138
139 @Subscribe
140 public void handleTableLoad(LoadTableEvent e) {
141
142 SynchroTableMetadata table = e.table;
143 SynchroDirection direction = getConfig().getDirection();
144
145 boolean hasStatusFilter = statusWhereClauseOrNull != null;
146 boolean hasUpdateDateColumn = hasColumns(table, DatabaseColumns.UPDATE_DT.name());
147 boolean hasStatusCdColumn = hasColumns(table, DatabaseColumns.STATUS_CD.name());
148 boolean isRoot = hasUpdateDateColumn
149 && (!hasStatusFilter || hasStatusCdColumn);
150
151
152
153
154
155
156
157 if (!table.isRoot() && isRoot) {
158 table.setRoot(true);
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173 if (direction == SynchroDirection.IMPORT_FILE2LOCAL) {
174
175
176 Collection<String> columnNames = naturalIds.get(table.getName());
177 if (CollectionUtils.isNotEmpty(columnNames)) {
178
179 SynchroTableMetadata.DuplicateKeyStrategy duplicateKeyStrategy = getConfig().getTableNamesForced().contains(table.getName()) ?
180 SynchroTableMetadata.DuplicateKeyStrategy.REPLACE_AND_REMAP :
181 SynchroTableMetadata.DuplicateKeyStrategy.REJECT_AND_REMAP;
182 table.addUniqueConstraint("NATURAL_ID_UNIQUE_C", ImmutableList.copyOf(columnNames), duplicateKeyStrategy);
183 }
184
185
186 if (table.isSimpleKey()) {
187
188 String pkName = table.getPkNames().iterator().next();
189 boolean isNumericPk = SynchroMetadataUtils.isNumericType(table.getColumnMetadata(pkName));
190
191 if (isNumericPk) {
192 int pkColumnIndex = table.getSelectColumnIndex(pkName);
193
194
195 Map<String, Integer> recursiveColumnIndexesByNames = recursiveColumnsByTable.get(table.getName());
196
197 ImportFromFileNumericalPkInterceptor pkInterceptor = new ImportFromFileNumericalPkInterceptor(
198 table.getName(),
199 pkName,
200 pkColumnIndex,
201 recursiveColumnIndexesByNames,
202 getConfig()
203 );
204 table.addInterceptor(pkInterceptor);
205 }
206 }
207 }
208 }
209
210
211
212
213
214
215
216
217
218 @Subscribe
219 public void handleJoinLoad(LoadJoinEvent e) {
220 SynchroJoinMetadata join = e.join;
221
222 SynchroTableMetadata fkTable = join.getFkTable();
223 String fkTableName = join.getFkTable().getName().toUpperCase();
224 String pkTableName = join.getPkTable().getName().toUpperCase();
225 String fkColumnName = join.getFkColumn().getName().toUpperCase();
226
227 boolean hasStatusFilter = statusWhereClauseOrNull != null;
228 boolean fkTableHasUpdateDateColumn = hasColumns(join.getFkTable(), DatabaseColumns.UPDATE_DT.name());
229 boolean fkTableHasStatusCdColumn = hasColumns(join.getFkTable(), DatabaseColumns.STATUS_CD.name());
230 boolean fkTableIsRoot = fkTableHasUpdateDateColumn
231 && (!hasStatusFilter || fkTableHasStatusCdColumn);
232 boolean isNumericColumn = SynchroMetadataUtils.isNumericType(fkTable.getColumnMetadata(fkColumnName));
233 SynchroDirection direction = getConfig().getDirection();
234
235
236 if (join.getFkTable() == join.getPkTable()) {
237 if (log.isDebugEnabled()) {
238 log.debug("Disable join: " + join.toString());
239 }
240 join.setIsValid(false);
241
242
243 if (direction == SynchroDirection.IMPORT_FILE2LOCAL
244 && isNumericColumn
245 && fkTable.isSimpleKey()) {
246
247
248 Map<String, Integer> recursiveColumnIndexesByName = recursiveColumnsByTable.computeIfAbsent(pkTableName, k -> Maps.newHashMap());
249 recursiveColumnIndexesByName.put(fkColumnName, fkTable.getSelectColumnIndex(fkColumnName));
250 }
251 return;
252 }
253
254
255 if (join.isChild() && fkTableIsRoot) {
256 if (log.isDebugEnabled()) {
257 log.debug("Disable join: " + join.toString());
258 }
259 join.setIsValid(false);
260 return;
261 }
262
263
264 else if (join.isChild() && fkTableHasUpdateDateColumn && hasStatusFilter) {
265
266 return;
267 }
268
269
270 if (join.isChild()) {
271
272 Collection<String> columnIncludes = childJoinIncludes.get(fkTableName);
273 boolean explicitlyInclude = CollectionUtils.isNotEmpty(columnIncludes) && columnIncludes.contains(fkColumnName);
274
275
276 Collection<String> columnExcludes = childJoinExcludes.get(fkTableName);
277 boolean explicitlyExclude = CollectionUtils.isNotEmpty(columnExcludes) && columnExcludes.contains(fkColumnName);
278
279 if (!explicitlyInclude || explicitlyExclude) {
280 if (log.isDebugEnabled()) {
281 log.debug("Disable join: " + join.toString());
282 }
283 join.setIsValid(false);
284 }
285 }
286
287
288 if (fkTable == e.source) {
289
290
291 if (direction == SynchroDirection.IMPORT_FILE2LOCAL
292 && isNumericColumn
293 && join.getPkTable().isSimpleKey()) {
294 int fkColumnIndex = fkTable.getSelectColumnIndex(fkColumnName);
295
296 ImportFromFileFkInterceptor fkInterceptor = new ImportFromFileFkInterceptor(
297 pkTableName,
298 fkColumnIndex,
299 getConfig());
300
301 if (!fkTable.containsInterceptor(fkInterceptor)) {
302 fkTable.addInterceptor(fkInterceptor);
303 }
304 }
305 }
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320 protected String createStatusWhereClauseOrNull(ReferentialSynchroDatabaseConfiguration config) {
321
322 Set<String> statusCodeIncludes = config.getStatusCodeIncludes();
323 if (CollectionUtils.isEmpty(statusCodeIncludes)) {
324 return null;
325 }
326
327 return String.format("t.%s IN ('%s')",
328 DatabaseColumns.STATUS_CD,
329 Joiner.on("','").join(statusCodeIncludes));
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 protected String addRestriction(SynchroTableMetadata table, SynchroQueryName queryName, String sql) {
346 SynchroQueryBuilder queryBuilder = SynchroQueryBuilder.newBuilder(sql);
347
348
349 if (hasColumns(table, DatabaseColumns.STATUS_CD.name())) {
350 if (statusWhereClauseOrNull != null) {
351 queryBuilder.addWhere(SynchroQueryOperator.AND, statusWhereClauseOrNull);
352 } else
353
354 if (queryName == SynchroQueryName.selectMaxUpdateDate) {
355
356 if (getConfig().getDirection() == SynchroDirection.IMPORT_TEMP2LOCAL) {
357 queryBuilder.addWhere(
358 SynchroQueryOperator.AND,
359 String.format("t.%s NOT IN ('%s', '%s')", DatabaseColumns.STATUS_CD.name(), StatusCode.LOCAL_ENABLE.getValue(),
360 StatusCode.LOCAL_DISABLE.getValue()));
361 }
362
363 else if (getConfig().getDirection() == SynchroDirection.IMPORT_FILE2LOCAL) {
364 queryBuilder.addWhere(SynchroQueryOperator.AND, "1 = 2");
365 }
366 }
367 }
368
369
370 String pkFilter = createPkFilter(table);
371 if (StringUtils.isNotBlank(pkFilter)) {
372
373 queryBuilder.addWhere(SynchroQueryOperator.AND, pkFilter);
374 }
375
376 return queryBuilder.build();
377 }
378
379
380
381
382
383
384
385
386 protected static Multimap<String, String> initChildJoinIncludes() {
387 Multimap<String, String> result = ArrayListMultimap.create();
388
389
390 result.put(ReferentialSynchroTables.CAMPAIGN_AREA.name(), "CAMPAIGN_ID");
391 result.put(ReferentialSynchroTables.CAMPAIGN_LINE.name(), "CAMPAIGN_ID");
392 result.put(ReferentialSynchroTables.CAMPAIGN_POINT.name(), "CAMPAIGN_ID");
393 result.put(ReferentialSynchroTables.CAMPAIGN_PROG.name(), "CAMPAIGN_ID");
394 result.put(ReferentialSynchroTables.DEPARTMENT_PRIVILEGE.name(), "DEP_ID");
395 result.put(ReferentialSynchroTables.EVENT_AREA.name(), "EVENT_ID");
396 result.put(ReferentialSynchroTables.EVENT_LINE.name(), "EVENT_ID");
397 result.put(ReferentialSynchroTables.EVENT_POINT.name(), "EVENT_ID");
398
399 result.put(ReferentialSynchroTables.FRACTION_MATRIX.name(), "MATRIX_ID");
400 result.put(ReferentialSynchroTables.FRACTION_MATRIX.name(), "FRACTION_ID");
401 result.put(ReferentialSynchroTables.MON_LOC_AREA.name(), "MON_LOC_ID");
402 result.put(ReferentialSynchroTables.MON_LOC_LINE.name(), "MON_LOC_ID");
403 result.put(ReferentialSynchroTables.MON_LOC_ORDER_ITEM.name(), "MON_LOC_ID");
404 result.put(ReferentialSynchroTables.MON_LOC_ORDER_ITEM.name(), "ORDER_ITEM_ID");
405 result.put(MetaProgramSynchroTables.MON_LOC_PMFM_MET.name(), "MON_LOC_MET_ID");
406 result.put(ReferentialSynchroTables.MON_LOC_POINT.name(), "MON_LOC_ID");
407 result.put(ReferentialSynchroTables.MON_LOC_PROG.name(), "PROG_CD");
408 result.put(MetaProgramSynchroTables.MON_LOC_MET.name(), "PROG_CD");
409 result.put(ReferentialSynchroTables.OCCAS_AREA.name(), "OCCAS_ID");
410 result.put(ReferentialSynchroTables.OCCAS_LINE.name(), "OCCAS_ID");
411 result.put(ReferentialSynchroTables.OCCAS_POINT.name(), "OCCAS_ID");
412 result.put(ReferentialSynchroTables.OCCAS_QUSER.name(), "OCCAS_ID");
413 result.put(ReferentialSynchroTables.PROG_DEP_PROG_PRIV.name(), "PROG_CD");
414 result.put(MetaProgramSynchroTables.PMFM_MET.name(), "MET_CD");
415 result.put(ReferentialSynchroTables.PMFM_QUAL_VALUE.name(), "PMFM_ID");
416 result.put(ReferentialSynchroTables.PMFM_STRAT_ACQUIS_LEVEL.name(), "PMFM_STRAT_ID");
417 result.put(ReferentialSynchroTables.PMFM_STRAT_UI_FUNCTION.name(), "PMFM_STRAT_ID");
418 result.put(ReferentialSynchroTables.PMFM_STRAT_PMFM_QUAL_VALUE.name(), "PMFM_STRAT_ID");
419 result.put(ReferentialSynchroTables.PROG_QUSER_PROG_PRIV.name(), "PROG_CD");
420 result.put(ContextAndFilterSynchroTables.PMFM_CONTEXT_ORDER.name(), "CONTEXT_ID");
421 result.put(ReferentialSynchroTables.QUSER_PRIVILEGE.name(), "QUSER_ID");
422 result.put(ReferentialSynchroTables.VIRTUAL_COMPONENT.name(), "REF_TAXON_ID");
423 result.put(ReferentialSynchroTables.TAXON_INFORMATION.name(), "TAXON_NAME_ID");
424 result.put(ReferentialSynchroTables.TAXON_INFORMATION_HISTORY.name(), "TAXON_NAME_HIST_ID");
425 result.put(ReferentialSynchroTables.TAXON_GROUP_INFORMATION.name(), "TAXON_GROUP_ID");
426 result.put(ReferentialSynchroTables.TAXON_GROUP_HISTORICAL_RECORD.name(), "TAXON_GROUP_ID");
427 result.put(ReferentialSynchroTables.TAXON_GROUP_POSITION.name(), "TAXON_GROUP_ID");
428 result.put(ReferentialSynchroTables.PRIVILEGE_TRANSFER.name(), "PRIV_TRANSFER_FROM_DEP_ID");
429 result.put(ReferentialSynchroTables.TAXON_POSITION.name(), "REF_TAXON_ID");
430 result.put(ReferentialSynchroTables.TAXON_POSITION.name(), "MON_LOC_ID");
431 result.put(ReferentialSynchroTables.AUTHOR_REF_DOC.name(), "REF_DOC_ID");
432
433
434 result.put(ReferentialSynchroTables.RESP_QUSER_STRAT.name(), "STRAT_ID");
435 result.put(ReferentialSynchroTables.RESP_DEP_STRAT.name(), "STRAT_ID");
436
437
438 result.put(ReferentialSynchroTables.STRATEGY.name(), "PROG_CD");
439 result.put(ReferentialSynchroTables.APPLIED_STRATEGY.name(), "STRAT_ID");
440 result.put(ReferentialSynchroTables.APPLIED_PERIOD.name(), "APPLIED_STRAT_ID");
441 result.put(ReferentialSynchroTables.PMFM_APPLIED_STRATEGY.name(), "APPLIED_STRAT_ID");
442 result.put(ReferentialSynchroTables.PMFM_STRATEGY.name(), "STRAT_ID");
443
444
445 result.put(ReferentialSynchroTables.MORATORIUM.name(), "PROG_CD");
446 result.put(ReferentialSynchroTables.MOR_MON_LOC_PROG.name(), "MOR_ID");
447 result.put(ReferentialSynchroTables.MOR_PERIOD.name(), "MOR_ID");
448 result.put(ReferentialSynchroTables.PMFM_MOR.name(), "MOR_ID");
449 result.put(ReferentialSynchroTables.MOR_CAMP.name(), "MOR_ID");
450 result.put(ReferentialSynchroTables.MOR_OCCAS.name(), "MOR_ID");
451
452 return result;
453 }
454
455
456
457
458
459
460
461
462 protected static Multimap<String, String> initChildJoinExcludes() {
463 Multimap<String, String> result = ArrayListMultimap.create();
464
465
466 result.put("TAXON_GROUP", "PARENT_TAXON_GROUP_FK");
467 result.put("PMFM_APPLIED_STRATEGY", "PMFM_STRAT_ID");
468
469 return result;
470 }
471
472
473
474
475
476
477
478
479 protected static Multimap<String, String> initNaturalIds() {
480 Multimap<String, String> result = MultimapBuilder.hashKeys().arrayListValues().build();
481 result.put(ReferentialSynchroTables.MONITORING_LOCATION.name(), DatabaseColumns.MON_LOC_NM.name());
482 result.putAll(ReferentialSynchroTables.TAXON_NAME.name(), ImmutableList.of(
483 DatabaseColumns.TAXON_NAME_COMPLETE_NM.name(),
484 DatabaseColumns.CIT_ID.name()));
485 result.put(ReferentialSynchroTables.TAXON_GROUP.name(), DatabaseColumns.TAXON_GROUP_NM.name());
486 result.put(ReferentialSynchroTables.PARAMETER.name(), DatabaseColumns.PAR_CD.name());
487 result.put(ReferentialSynchroTables.MATRIX.name(), DatabaseColumns.MATRIX_NM.name());
488 result.put(ReferentialSynchroTables.FRACTION.name(), DatabaseColumns.FRACTION_NM.name());
489 result.put(ReferentialSynchroTables.METHOD.name(), DatabaseColumns.METHOD_NM.name());
490 result.putAll(ReferentialSynchroTables.QUALITATIVE_VALUE.name(), ImmutableList.of(
491 DatabaseColumns.QUAL_VALUE_NM.name(),
492 DatabaseColumns.PAR_CD.name()));
493
494
495 result.putAll(ReferentialSynchroTables.PMFM.name(), ImmutableList.of(
496 DatabaseColumns.PAR_CD.name(),
497 DatabaseColumns.MATRIX_ID.name(),
498 DatabaseColumns.FRACTION_ID.name(),
499 DatabaseColumns.METHOD_ID.name(),
500 DatabaseColumns.UNIT_ID.name()));
501
502 result.putAll(ReferentialSynchroTables.UNIT.name(), ImmutableList.of(
503 DatabaseColumns.UNIT_NM.name(),
504 DatabaseColumns.UNIT_SYMBOL.name()));
505 result.put(ReferentialSynchroTables.ANALYSIS_INSTRUMENT.name(), DatabaseColumns.ANAL_INST_NM.name());
506 result.put(ReferentialSynchroTables.SAMPLING_EQUIPMENT.name(), DatabaseColumns.SAMPLING_EQUIPMENT_NM.name());
507 result.put(ReferentialSynchroTables.PROGRAMME.name(), DatabaseColumns.PROG_CD.name());
508 result.putAll(ReferentialSynchroTables.STRATEGY.name(), ImmutableList.of(
509 DatabaseColumns.PROG_CD.name(),
510 DatabaseColumns.STRAT_NM.name()));
511 result.put(ReferentialSynchroTables.QUSER.name(), DatabaseColumns.QUSER_INTRANET_LG.name());
512 result.put(ReferentialSynchroTables.DEPARTMENT.name(), DatabaseColumns.DEP_CD.name());
513
514 return result;
515 }
516
517 }