OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
182 ilm 4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
17 ilm 5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.sql.model;
15
 
83 ilm 16
import org.openconcerto.sql.Configuration;
182 ilm 17
import org.openconcerto.sql.element.SQLElement;
73 ilm 18
import org.openconcerto.sql.model.graph.SQLKey;
19
import org.openconcerto.sql.model.graph.TablesMap;
83 ilm 20
import org.openconcerto.sql.preferences.SQLPreferences;
73 ilm 21
import org.openconcerto.sql.utils.AlterTable;
22
import org.openconcerto.sql.utils.ChangeTable;
23
import org.openconcerto.sql.utils.SQLCreateTable;
24
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
83 ilm 25
import org.openconcerto.utils.StringUtils;
73 ilm 26
import org.openconcerto.utils.cc.ITransformer;
17 ilm 27
 
28
import java.sql.SQLException;
177 ilm 29
import java.text.DateFormat;
30
import java.text.SimpleDateFormat;
17 ilm 31
import java.util.ArrayList;
73 ilm 32
import java.util.Arrays;
17 ilm 33
import java.util.HashMap;
177 ilm 34
import java.util.HashSet;
73 ilm 35
import java.util.List;
17 ilm 36
import java.util.Map;
73 ilm 37
import java.util.Set;
17 ilm 38
 
39
public class SQLInjector {
40
 
73 ilm 41
    private final SQLTable tableSrc, tableDest;
42
    private final ArrayList<SQLField> from = new ArrayList<SQLField>();
43
    private final ArrayList<SQLField> to = new ArrayList<SQLField>();
44
    private final Map<SQLField, Object> values = new HashMap<SQLField, Object>();
45
    private final static Map<DBRoot, Map<SQLTable, Map<SQLTable, SQLInjector>>> allRegisteredInjectors = new HashMap<DBRoot, Map<SQLTable, Map<SQLTable, SQLInjector>>>();
17 ilm 46
 
73 ilm 47
    private boolean storeTransfer;
48
    // maps of injectors that store transfer
49
    private static Map<DBRoot, Map<SQLTable, Map<SQLTable, SQLInjector>>> injectors = new HashMap<DBRoot, Map<SQLTable, Map<SQLTable, SQLInjector>>>();
50
 
51
    public SQLInjector(final DBRoot r, final String src, final String dest, boolean storeTransfer) {
52
        this(r.findTable(src), r.findTable(dest), storeTransfer);
17 ilm 53
    }
54
 
73 ilm 55
    public SQLInjector(SQLTable src, SQLTable dest, boolean storeTransfer) {
17 ilm 56
        this.tableDest = dest;
57
        this.tableSrc = src;
73 ilm 58
        this.storeTransfer = storeTransfer;
59
        final DBRoot dbRoot = src.getDBRoot();
60
        Map<SQLTable, Map<SQLTable, SQLInjector>> inj = allRegisteredInjectors.get(dbRoot);
61
        if (inj == null) {
62
            inj = new HashMap<SQLTable, Map<SQLTable, SQLInjector>>();
63
            allRegisteredInjectors.put(dbRoot, inj);
64
        }
65
        Map<SQLTable, SQLInjector> srcs = inj.get(src);
17 ilm 66
        if (srcs == null) {
67
            srcs = new HashMap<SQLTable, SQLInjector>();
73 ilm 68
            inj.put(src, srcs);
17 ilm 69
        }
70
        srcs.put(dest, this);
73 ilm 71
 
72
        if (storeTransfer) {
73
            // Register only SQLInjector that store transfer
74
            inj = injectors.get(dbRoot);
75
            if (inj == null) {
76
                inj = new HashMap<SQLTable, Map<SQLTable, SQLInjector>>();
77
                injectors.put(dbRoot, inj);
78
            }
79
            srcs = inj.get(src);
80
            if (srcs == null) {
81
                srcs = new HashMap<SQLTable, SQLInjector>();
82
                inj.put(src, srcs);
83
            }
84
            srcs.put(dest, this);
85
        }
17 ilm 86
    }
87
 
73 ilm 88
    public synchronized SQLRowValues createRowValuesFrom(int idSrc) {
89
        final List<SQLRowAccessor> srcRows = new ArrayList<SQLRowAccessor>(1);
93 ilm 90
        srcRows.add(getSource().getRow(idSrc));
73 ilm 91
        return createRowValuesFrom(srcRows);
17 ilm 92
    }
93
 
73 ilm 94
    public synchronized SQLRowValues createRowValuesFrom(final SQLRow srcRow) {
95
        final SQLRowValues rowVals = new SQLRowValues(getDestination());
17 ilm 96
        if (!srcRow.getTable().equals(getSource()))
97
            throw new IllegalArgumentException("Row not from source table : " + srcRow);
73 ilm 98
        merge(srcRow, rowVals);
99
        return rowVals;
100
    }
17 ilm 101
 
73 ilm 102
    public synchronized SQLRowValues createRowValuesFrom(final List<? extends SQLRowAccessor> srcRows) {
103
        final SQLRowValues rowVals = new SQLRowValues(getDestination());
104
        for (SQLRowAccessor srcRow : srcRows) {
105
            if (!srcRow.getTable().equals(getSource()))
106
                throw new IllegalArgumentException("Row not from source table : " + srcRow);
107
            merge(srcRow, rowVals);
108
        }
109
        return rowVals;
110
    }
111
 
112
    public void commitTransfert(final List<? extends SQLRowAccessor> srcRows, int destId) throws SQLException {
113
 
114
        if (storeTransfer) {
115
            System.err.println("SQLInjector.commitTransfert() : transfert from " + this.getSource().getName() + " to " + this.getDestination().getName());
116
            // Transfert
117
            final SQLTable tableTransfert = getSource().getDBRoot().getTable(getTableTranferName());
118
            if (tableTransfert == null) {
119
                throw new IllegalStateException("No table transfer for " + getSource().getName());
120
            }
121
 
122
            for (SQLRowAccessor srcRow : srcRows) {
123
 
124
                final SQLRowValues rowTransfer = new SQLRowValues(tableTransfert);
125
 
126
                final Set<SQLField> foreignKeysSrc = tableTransfert.getForeignKeys(getSource());
127
                final Set<SQLField> foreignKeysDest = tableTransfert.getForeignKeys(getDestination());
128
                if (foreignKeysSrc.isEmpty()) {
129
                    throw new IllegalStateException("No foreign (src) to " + getSource().getName() + " in " + tableTransfert.getName());
130
                }
131
                if (foreignKeysDest.isEmpty()) {
132
                    throw new IllegalStateException("No foreign (dest) to " + getDestination().getName() + " in " + tableTransfert.getName());
133
                }
134
                rowTransfer.put(foreignKeysSrc.iterator().next().getName(), srcRow.getIDNumber());
135
                rowTransfer.put(foreignKeysDest.iterator().next().getName(), destId);
136
                // TODO: commit in one shot
137
                rowTransfer.commit();
138
 
139
            }
140
        }
141
 
142
    }
143
 
144
    private String getTableTranferName() {
145
        return "TR_" + getSource().getName();
146
    }
147
 
148
    protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
17 ilm 149
        for (SQLField field : this.values.keySet()) {
150
            rowVals.put(field.getName(), this.values.get(field));
151
        }
73 ilm 152
        final SQLSystem dbSystem = srcRow.getTable().getDBSystemRoot().getServer().getSQLSystem();
153
        final int size = getFrom().size();
154
        for (int i = 0; i < size; i++) {
17 ilm 155
 
156
            final SQLField sqlFieldFrom = getFrom().get(i);
157
            final SQLField sqlFieldTo = getTo().get(i);
158
            final Object o = srcRow.getObject(sqlFieldFrom.getName());
159
 
160
            // Probleme avec H2 Primary Key en Long et foreignKey en Int
161
            if (dbSystem == SQLSystem.H2 && sqlFieldFrom.getType().getJavaType() == Long.class && sqlFieldTo.getType().getJavaType() == Integer.class) {
73 ilm 162
                merge(sqlFieldTo, ((Long) o).intValue(), rowVals);
17 ilm 163
            } else {
73 ilm 164
                merge(sqlFieldTo, o, rowVals);
17 ilm 165
            }
166
        }
73 ilm 167
    }
17 ilm 168
 
73 ilm 169
    protected void merge(SQLField field, Object value, SQLRowValues rowVals) {
170
        rowVals.put(field.getName(), value);
17 ilm 171
    }
172
 
180 ilm 173
    private String cleanRef(String value) {
174
        List<String> l = StringUtils.fastSplit(value, ',');
175
        Set<String> s = new HashSet<>(l);
176
        String nom = "";
177
        if (s.size() > 1) {
178
            Set<String> refAdded = new HashSet<>();
179
            for (String string : s) {
180
                if (string.trim().length() > 0 && !refAdded.contains(string.trim())) {
181
                    nom += string + ",";
182
                    refAdded.add(string.trim());
183
                }
184
            }
185
        } else if (s.size() == 1) {
186
            nom = s.iterator().next();
187
        }
188
        return nom;
189
    }
190
 
174 ilm 191
    protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField, String from, String to) {
83 ilm 192
 
193
        String label = rowVals.getString(to);
174 ilm 194
        SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
195
 
196
        if (prefs.getBoolean("TransfertRef", true) || !to.equals("NOM")) {
197
            if (label != null && label.trim().length() > 0) {
180 ilm 198
                rowVals.put(to, cleanRef(label + ", " + srcRow.getString(from)));
174 ilm 199
            } else {
200
                rowVals.put(to, srcRow.getString(from));
201
            }
202
        } else if (prefs.getBoolean("TransfertMultiRef", false)) {
203
            SQLRowValues rowValsHeader = new SQLRowValues(UndefinedRowValuesCache.getInstance().getDefaultRowValues(tableElementDestination));
204
            // TODO taxe may be undefined set it to default
205
            rowValsHeader.put("NOM", srcRow.getString(from));
206
            rowValsHeader.put(refField, rowVals);
83 ilm 207
        }
174 ilm 208
 
83 ilm 209
    }
210
 
177 ilm 211
    DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
212
 
83 ilm 213
    protected void transfertNumberReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField) {
174 ilm 214
        SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
83 ilm 215
 
216
        if (prefs.getBoolean("TransfertRef", true)) {
217
            String label = rowVals.getString("NOM");
218
            if (label != null && label.trim().length() > 0) {
177 ilm 219
                final String value = label + ", " + srcRow.getString("NUMERO");
180 ilm 220
                rowVals.put("NOM", cleanRef(value));
83 ilm 221
            } else {
222
                rowVals.put("NOM", srcRow.getString("NUMERO"));
223
            }
224
        } else if (prefs.getBoolean("TransfertMultiRef", false)) {
225
            SQLRowValues rowValsHeader = new SQLRowValues(UndefinedRowValuesCache.getInstance().getDefaultRowValues(tableElementDestination));
177 ilm 226
            // FIXME Style forcé en titre 1 via l'ID
227
            rowValsHeader.put("ID_STYLE", 3);
182 ilm 228
            SQLElement element = Configuration.getInstance().getDirectory().getElement(getSource());
229
            //Utiliser pour les transfert du module commande interne
230
            if (element == null) {
231
                element = Configuration.getInstance().getDirectory().getElement(getSource().getName());
232
            }
233
 
234
            String elementName = StringUtils.firstUp(element.getName().getVariant(org.openconcerto.utils.i18n.Grammar.SINGULAR));
177 ilm 235
            rowValsHeader.put("NOM", elementName + "\n N° " + srcRow.getString("NUMERO") + " du " + dateFormat.format(srcRow.getDate("DATE").getTime()));
83 ilm 236
            rowValsHeader.put(refField, rowVals);
237
        }
238
    }
239
 
73 ilm 240
    public synchronized SQLRow insertFrom(final SQLRowAccessor srcRow) throws SQLException {
241
        return createRowValuesFrom(Arrays.asList(srcRow)).insert();
17 ilm 242
    }
243
 
244
    // TODO gettable()..getName()..equalsIgnoreCase( by .getTable().equals(
245
    /**
246
     * mettre une valeur par défaut pour un champ donné
247
     *
248
     * @param fieldDest
249
     * @param defaultValue
250
     */
73 ilm 251
    protected synchronized final void mapDefaultValues(SQLField fieldDest, Object defaultValue) {
17 ilm 252
        if (fieldDest.getTable().getName().equalsIgnoreCase(this.tableDest.getName())) {
253
            this.values.put(fieldDest, defaultValue);
254
        } else {
255
            throw new IllegalArgumentException("SQLField " + fieldDest + " is not a field of table " + this.tableDest);
256
        }
257
    }
258
 
73 ilm 259
    protected synchronized final void map(SQLField from, SQLField to) throws IllegalArgumentException {
17 ilm 260
        // Verification de la validité des SQLField
261
        if (!from.getTable().getName().equalsIgnoreCase(this.tableSrc.getName())) {
262
            throw new IllegalArgumentException("SQLField " + from + " is not a field of table " + this.tableSrc);
263
        } else {
264
            if (!to.getTable().getName().equalsIgnoreCase(this.tableDest.getName())) {
265
                throw new IllegalArgumentException("SQLField " + to + " is not a field of table " + this.tableDest);
266
            }
267
        }
268
 
269
        int index = this.from.indexOf(from);
270
        if (index > 0) {
271
            this.to.set(index, to);
272
        } else {
273
            this.from.add(from);
274
            this.to.add(to);
275
        }
276
    }
277
 
73 ilm 278
    protected synchronized final void remove(SQLField from, SQLField to) throws IllegalArgumentException {
17 ilm 279
        // Verification de la validité des SQLField
280
        if (!from.getTable().getName().equalsIgnoreCase(this.tableSrc.getName())) {
281
            throw new IllegalArgumentException("SQLField " + from + " is not a field of table " + this.tableSrc);
282
        } else {
283
            if (!to.getTable().getName().equalsIgnoreCase(this.tableDest.getName())) {
284
                throw new IllegalArgumentException("SQLField " + to + " is not a field of table " + this.tableDest);
285
            }
286
        }
287
 
288
        int index = this.from.indexOf(from);
289
        if (this.to.get(index).getName().equalsIgnoreCase(to.getName())) {
290
            this.to.remove(to);
291
            this.from.remove(from);
292
        }
293
    }
294
 
295
    /**
296
     * Créer l'association entre les champs portant le nom dans les deux tables
297
     *
298
     */
73 ilm 299
    public synchronized void createDefaultMap() {
17 ilm 300
        for (SQLField field : this.tableSrc.getContentFields()) {
301
 
302
            if (this.tableDest.contains(field.getName())) {
303
                map(field, this.tableDest.getField(field.getName()));
304
            }
305
        }
306
    }
307
 
73 ilm 308
    public synchronized ArrayList<SQLField> getFrom() {
17 ilm 309
        return this.from;
310
    }
311
 
73 ilm 312
    public synchronized ArrayList<SQLField> getTo() {
17 ilm 313
        return this.to;
314
    }
315
 
316
    /**
317
     * Creer un SQLInjector par défaut si aucun n'est déja défini
318
     *
319
     * @param src
320
     * @param dest
321
     * @return un SQLInjector par défaut si aucun n'est déja défini
322
     */
73 ilm 323
    public static synchronized SQLInjector getInjector(SQLTable src, SQLTable dest) {
324
        SQLInjector injector = getRegistrereddInjector(src, dest);
325
        if (injector == null) {
326
            injector = createDefaultInjector(src, dest);
17 ilm 327
        }
73 ilm 328
        return injector;
17 ilm 329
    }
330
 
73 ilm 331
    public static synchronized SQLInjector getRegistrereddInjector(SQLTable src, SQLTable dest) {
332
        final Map<SQLTable, Map<SQLTable, SQLInjector>> map = allRegisteredInjectors.get(src.getDBRoot());
333
        if (map == null) {
334
            return null;
335
        }
336
        Map<SQLTable, SQLInjector> m = map.get(src);
337
        if (m != null) {
338
            return m.get(dest);
339
        }
340
        return null;
341
    }
342
 
343
    private static synchronized SQLInjector createDefaultInjector(SQLTable src, SQLTable dest) {
344
        System.err.println("No SQLInjector defined for " + src + " , " + dest + ". SQLInjector created automatically.");
345
        SQLInjector injector = new SQLInjector(src, dest, false);
346
        injector.createDefaultMap();
347
        return injector;
348
    }
349
 
350
    public synchronized SQLTable getDestination() {
17 ilm 351
        return this.tableDest;
352
    }
353
 
73 ilm 354
    public synchronized SQLTable getSource() {
17 ilm 355
        return this.tableSrc;
356
    }
73 ilm 357
 
358
    public synchronized static void createTransferTables(DBRoot root) throws SQLException {
359
        Map<SQLTable, Map<SQLTable, SQLInjector>> map = injectors.get(root);
360
        if (root == null) {
361
            System.err.println("No SQLInjector for root " + root);
362
            return;
363
        }
364
 
365
        final Set<SQLTable> srcTables = map.keySet();
366
        if (srcTables.isEmpty()) {
367
            System.err.println("No SQLInjector for root " + root);
368
            return;
369
        }
370
 
371
        final List<SQLCreateTable> createTablesQueries = new ArrayList<SQLCreateTable>();
372
        // Create table if needed
373
        for (SQLTable sqlTable : srcTables) {
374
            final String trTableName = "TR_" + sqlTable.getName();
375
            if (root.getTable(trTableName) == null) {
376
                final SQLCreateTable createTable = new SQLCreateTable(root, trTableName);
377
                createTable.setPlain(false);
378
                // createTable.addColumn(SQLSyntax.ID_NAME,
379
                // createTable.getSyntax().getPrimaryIDDefinition());
380
                createTable.addForeignColumn(SQLKey.PREFIX + sqlTable.getName(), sqlTable);
381
                createTablesQueries.add(createTable);
382
            }
383
        }
384
        if (createTablesQueries.size() > 0) {
385
            root.createTables(createTablesQueries);
386
        }
387
 
388
        // Create transfer fields if needed
389
        final List<AlterTable> alterTablesQueries = new ArrayList<AlterTable>();
390
        final TablesMap toRefresh = new TablesMap();
391
        for (SQLTable srcTable : srcTables) {
392
            final String trTableName = "TR_" + srcTable.getName();
393
            final SQLTable transfertTable = root.getTable(trTableName);
394
            final AlterTable alter = new AlterTable(transfertTable);
395
            final Set<SQLTable> destTables = map.get(srcTable).keySet();
396
            for (SQLTable destTable : destTables) {
397
                final String fk = SQLKey.PREFIX + destTable.getName();
398
                if (!transfertTable.contains(fk)) {
399
                    alter.addForeignColumn(fk, destTable);
400
                }
401
            }
402
            if (!alter.isEmpty()) {
403
                alterTablesQueries.add(alter);
404
                toRefresh.add(alter.getRootName(), alter.getName());
405
            }
406
        }
407
        for (final String q : ChangeTable.cat(alterTablesQueries)) {
408
            root.getDBSystemRoot().getDataSource().execute(q);
409
        }
410
        root.getSchema().updateVersion();
411
        root.getDBSystemRoot().refresh(toRefresh, false);
412
 
413
    }
414
 
415
    public void setOnlyTransfered(SQLTableModelSourceOnline tableSource) {
416
        // needed for distinct
417
        tableSource.getReq().setLockSelect(false);
418
 
419
        tableSource.getReq().setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
420
 
421
            @Override
422
            public SQLSelect transformChecked(SQLSelect input) {
423
 
424
                final SQLTable tableTR = getSource().getTable(getTableTranferName());
425
                // FIXME: preprocess TR_ .. content before join : group by id_src
426
                final SQLSelectJoin j = input.addBackwardJoin("INNER", null, tableTR.getForeignKeys(getSource()).iterator().next(), null);
427
                j.setWhere(new Where(tableTR.getForeignKeys(getDestination()).iterator().next(), "!=", getDestination().getUndefinedID()));
428
                input.setDistinct(true);
429
 
430
                System.err.println(input.asString());
431
                return input;
432
            }
433
        });
434
    }
435
 
436
    public void setOnlyNotTransfered(SQLTableModelSourceOnline tableSource) {
437
        tableSource.getReq().setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
438
 
439
            @Override
440
            public SQLSelect transformChecked(SQLSelect input) {
441
                final SQLTable tableTR = getSource().getTable(getTableTranferName());
442
 
443
                final Where w = new Where(tableTR.getForeignKeys(getSource()).iterator().next(), "=", input.getAlias(getSource().getKey()));
444
                input.addJoin("LEFT", tableTR, w);
445
                final Where w2 = new Where(tableTR.getForeignKeys(getDestination()).iterator().next(), "IS", (Object) null);
446
                input.setWhere(w2);
447
 
448
                System.err.println(input.asString());
449
                return input;
450
            }
451
        });
452
    }
453
 
454
    /**
455
     * register manually a transfer, use with caution
456
     *
457
     * @throws SQLException
174 ilm 458
     */
73 ilm 459
    public void addTransfert(int idFrom, int idTo) throws SQLException {
460
        final SQLTable tableTransfert = getSource().getTable(getTableTranferName());
461
        final SQLRowValues rowTransfer = new SQLRowValues(tableTransfert);
462
        final Set<SQLField> foreignKeysSrc = tableTransfert.getForeignKeys(getSource());
463
        final Set<SQLField> foreignKeysDest = tableTransfert.getForeignKeys(getDestination());
464
        rowTransfer.put(foreignKeysSrc.iterator().next().getName(), idFrom);
465
        rowTransfer.put(foreignKeysDest.iterator().next().getName(), idTo);
466
        rowTransfer.commit();
467
 
468
    }
469
 
17 ilm 470
}