1 package fr.ifremer.quadrige3.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.quadrige3.synchro.intercept.referential.AbstractReferentialInterceptor;
44 import fr.ifremer.quadrige3.synchro.intercept.referential.internal.ImportFromFileFkInterceptor;
45 import fr.ifremer.quadrige3.synchro.meta.DatabaseColumns;
46 import fr.ifremer.quadrige3.synchro.meta.system.RuleSynchroTables;
47 import fr.ifremer.quadrige3.synchro.service.SynchroDirection;
48 import fr.ifremer.quadrige3.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 private static final Multimap<String, String> naturalIds;
67
68 private static final Multimap<String, String> childJoinIncludes;
69
70 private 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 result.put(RuleSynchroTables.RULE_GROUP.name(), DatabaseColumns.RULE_CD.name());
110
111 return result;
112 }
113
114
115
116
117
118
119
120
121 protected static Multimap<String, String> initChildJoinExcludes() {
122
123 Multimap<String, String> result = ArrayListMultimap.create();
124
125
126 result.put(RuleSynchroTables.RULE_PRECONDITION.name(), DatabaseColumns.USED_RULE_CD.name());
127
128 return result;
129 }
130
131
132
133
134
135
136
137
138 protected static Multimap<String, String> initNaturalIds() {
139
140 Multimap<String, String> result = MultimapBuilder.hashKeys().arrayListValues().build();
141
142
143 result.putAll(RuleSynchroTables.RULE_LIST.name(), ImmutableList.of(
144 DatabaseColumns.RULE_LIST_CD.name()));
145
146 result.putAll(RuleSynchroTables.RULE.name(), ImmutableList.of(
147 DatabaseColumns.RULE_CD.name()));
148
149 return result;
150 }
151
152
153 @Override
154 protected void init(ReferentialSynchroDatabaseConfiguration config) {
155 super.init(config);
156 statusWhereClause = createStatusWhereClause(config);
157 setEnableOnWrite(true);
158 }
159
160
161 @Override
162 public SynchroInterceptorBase clone() {
163 RuleTableInterceptor result = (RuleTableInterceptor) super.clone();
164 result.statusWhereClause = this.statusWhereClause;
165 return result;
166 }
167
168
169
170
171
172
173
174
175
176
177
178 @Subscribe
179 public void handleQuery(CreateQueryEvent e) {
180
181 switch (e.queryName) {
182 case count:
183 case countFromUpdateDate:
184 case select:
185 case selectFromUpdateDate:
186 case selectMaxUpdateDate:
187
188 e.sql = addRestriction(e.source, e.queryName, e.sql);
189
190 default:
191 break;
192 }
193 }
194
195
196
197
198
199
200
201
202
203 @Subscribe
204 public void handleTableLoad(LoadTableEvent e) {
205
206 SynchroTableMetadata table = e.table;
207 SynchroDirection direction = getConfig().getDirection();
208
209 boolean hasStatusFilter = statusWhereClause != null;
210 boolean hasUpdateDateColumn = hasColumns(table, DatabaseColumns.UPDATE_DT.name());
211 boolean hasStatusCdColumn = hasColumns(table, DatabaseColumns.STATUS_CD.name());
212 boolean isRoot = hasUpdateDateColumn && (!hasStatusFilter || hasStatusCdColumn);
213
214
215
216
217
218
219 if (!table.isRoot() && isRoot) {
220 table.setRoot(true);
221 }
222
223
224
225 String tableName = table.getName();
226 boolean isRootWithoutStatusCd = !hasStatusCdColumn && hasStatusFilter
227 && (tableName.equalsIgnoreCase(RuleSynchroTables.RULE_LIST.name()));
228 if (!table.isRoot() && isRootWithoutStatusCd) {
229 table.setRoot(true);
230 }
231
232
233 if (direction == SynchroDirection.IMPORT_FILE2LOCAL) {
234 Collection<String> columnNames = naturalIds.get(table.getName());
235 if (CollectionUtils.isNotEmpty(columnNames)) {
236 table.addUniqueConstraint("NATURAL_ID_UNIQUE_C", ImmutableList.copyOf(columnNames),
237 SynchroTableMetadata.DuplicateKeyStrategy.REPLACE_AND_REMAP);
238 }
239 }
240 }
241
242
243
244
245
246
247
248
249
250 @Subscribe
251 public void handleJoinLoad(LoadJoinEvent e) {
252 SynchroJoinMetadata join = e.join;
253
254 SynchroTableMetadata fkTable = join.getFkTable();
255 String fkTableName = join.getFkTable().getName().toUpperCase();
256 String pkTableName = join.getPkTable().getName().toUpperCase();
257 String fkColumnName = join.getFkColumn().getName().toUpperCase();
258
259 boolean hasStatusFilter = statusWhereClause != null;
260 boolean fkTableHasUpdateDateColumn = hasColumns(join.getFkTable(), DatabaseColumns.UPDATE_DT.name());
261 boolean fkTableHasStatusCdColumn = hasColumns(join.getFkTable(), DatabaseColumns.STATUS_CD.name());
262 boolean fkTableIsRoot = fkTableHasUpdateDateColumn && (!hasStatusFilter || fkTableHasStatusCdColumn);
263 boolean isNumericColumn = SynchroMetadataUtils.isNumericType(fkTable.getColumnMetadata(fkColumnName));
264 SynchroDirection direction = getConfig().getDirection();
265
266
267 if (join.getFkTable() == join.getPkTable()) {
268 if (log.isDebugEnabled()) {
269 log.debug("Disable join: " + join.toString());
270 }
271 join.setIsValid(false);
272 return;
273 }
274
275
276 if (join.isChild() && fkTableIsRoot) {
277 if (log.isDebugEnabled()) {
278 log.debug("Disable join: " + join.toString());
279 }
280 join.setIsValid(false);
281 return;
282 } else if (join.isChild() && fkTableHasUpdateDateColumn && hasStatusFilter) {
283
284 return;
285 }
286
287
288 if (join.isChild()) {
289
290 Collection<String> columnIncludes = childJoinIncludes.get(fkTableName);
291 boolean explicitlyInclude = CollectionUtils.isNotEmpty(columnIncludes) && columnIncludes.contains(fkColumnName);
292
293
294 Collection<String> columnExcludes = childJoinExcludes.get(fkTableName);
295 boolean explicitlyExclude = CollectionUtils.isNotEmpty(columnExcludes) && columnExcludes.contains(fkColumnName);
296
297 if (!explicitlyInclude || explicitlyExclude) {
298 if (log.isDebugEnabled()) {
299 log.debug("Disable join: " + join.toString());
300 }
301 join.setIsValid(false);
302 }
303 }
304
305
306
307 if (fkTable == e.source) {
308
309
310 if (direction == SynchroDirection.IMPORT_FILE2LOCAL
311 && isNumericColumn
312 && join.getPkTable().isSimpleKey()) {
313 int fkColumnIndex = fkTable.getSelectColumnIndex(fkColumnName);
314
315 ImportFromFileFkInterceptor fkInterceptor = new ImportFromFileFkInterceptor(
316 pkTableName,
317 fkColumnIndex,
318 getConfig());
319
320 if (!fkTable.containsInterceptor(fkInterceptor)) {
321 fkTable.addInterceptor(fkInterceptor);
322 }
323 }
324 }
325 }
326
327
328
329
330
331
332
333
334
335
336 protected String createStatusWhereClause(SynchroDatabaseConfiguration config) {
337
338 Set<String> statusToInclude = getConfig().getStatusCodeIncludes();
339 if (CollectionUtils.isEmpty(statusToInclude)) {
340 return null;
341 }
342
343 return String.format("t.%s IN ('%s')",
344 DatabaseColumns.STATUS_CD,
345 Joiner.on("','").join(statusToInclude));
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 protected String addRestriction(SynchroTableMetadata table, SynchroQueryName queryName, String sql) {
362 SynchroQueryBuilder queryBuilder = SynchroQueryBuilder.newBuilder(sql);
363
364
365 if (statusWhereClause != null
366 && hasColumns(table, DatabaseColumns.STATUS_CD.name())) {
367 queryBuilder.addWhere(SynchroQueryOperator.AND, statusWhereClause);
368 }
369
370 return queryBuilder.build();
371 }
372 }