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