OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 177 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 177 Rev 182
Line 1... Line 1...
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
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
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
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.
9
 * language governing permissions and limitations under the License.
Line 12... Line 12...
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.sql.view.list;
14
 package org.openconcerto.sql.view.list;
15
 
15
 
16
import org.openconcerto.sql.Log;
16
import org.openconcerto.sql.Log;
-
 
17
import org.openconcerto.sql.model.RowRef;
17
import org.openconcerto.sql.model.SQLRow;
18
import org.openconcerto.sql.model.SQLRow;
-
 
19
import org.openconcerto.sql.model.SQLRowAccessor;
18
import org.openconcerto.sql.model.SQLRowValues;
20
import org.openconcerto.sql.model.SQLRowValues;
19
import org.openconcerto.sql.model.SQLRowValues.CreateMode;
-
 
20
import org.openconcerto.sql.model.SQLRowValuesCluster.State;
21
import org.openconcerto.sql.model.SQLRowValuesCluster.State;
21
import org.openconcerto.sql.model.SQLTable;
22
import org.openconcerto.sql.model.SQLTable;
22
import org.openconcerto.sql.model.SQLTableEvent;
23
import org.openconcerto.sql.model.SQLTableEvent;
23
import org.openconcerto.sql.model.SQLTableModifiedListener;
24
import org.openconcerto.sql.model.SQLTableModifiedListener;
24
import org.openconcerto.sql.model.graph.Link.Direction;
25
import org.openconcerto.sql.model.graph.Link.Direction;
25
import org.openconcerto.sql.model.graph.Path;
26
import org.openconcerto.sql.model.graph.Path;
-
 
27
import org.openconcerto.sql.request.ComboSQLRequest.KeepMode;
26
import org.openconcerto.sql.view.list.UpdateRunnable.RmAllRunnable;
28
import org.openconcerto.sql.view.list.UpdateRunnable.RmAllRunnable;
27
import org.openconcerto.sql.view.list.search.SearchOne;
29
import org.openconcerto.sql.view.list.search.SearchOne;
28
import org.openconcerto.sql.view.list.search.SearchOne.Mode;
30
import org.openconcerto.sql.view.list.search.SearchOne.Mode;
29
import org.openconcerto.sql.view.list.search.SearchQueue;
31
import org.openconcerto.sql.view.list.search.SearchQueue;
30
import org.openconcerto.sql.view.list.search.SearchQueue.SetStateRunnable;
32
import org.openconcerto.sql.view.list.search.SearchQueue.SetStateRunnable;
Line 45... Line 47...
45
import java.util.HashSet;
47
import java.util.HashSet;
46
import java.util.Iterator;
48
import java.util.Iterator;
47
import java.util.List;
49
import java.util.List;
48
import java.util.Set;
50
import java.util.Set;
49
import java.util.concurrent.RunnableFuture;
51
import java.util.concurrent.RunnableFuture;
-
 
52
import java.util.function.BiConsumer;
50
import java.util.logging.Level;
53
import java.util.logging.Level;
51
 
54
 
52
import net.jcip.annotations.GuardedBy;
55
import net.jcip.annotations.GuardedBy;
53
 
56
 
54
public final class UpdateQueue extends SleepingQueue {
57
public final class UpdateQueue extends SleepingQueue {
Line 197... Line 200...
197
        }
200
        }
198
        return res;
201
        return res;
199
    }
202
    }
200
 
203
 
201
    /**
204
    /**
202
     * The lines and their path affected by a change of the passed row.
205
     * The lines affected by a change of the passed row.
203
     * 
206
     * 
204
     * @param r the row that has changed.
207
     * @param r the row that has changed.
205
     * @return the refreshed lines and their changed paths.
208
     * @return the refreshed lines.
206
     */
209
     */
207
    protected final ListMap<ListSQLLine, Path> getAffectedLines(final SQLRow r) {
210
    protected final Set<Integer> getAffectedLines(final SQLRow r) {
-
 
211
        final Set<Integer> res = new HashSet<>();
208
        return this.getAffected(r, new ListMap<ListSQLLine, Path>(), true);
212
        this.getAffected(r, (p, l) -> res.add(l.getID()));
-
 
213
        return res;
209
    }
214
    }
210
 
215
 
211
    protected final ListMap<Path, ListSQLLine> getAffectedPaths(final SQLRow r) {
216
    protected final ListMap<Path, ListSQLLine> getAffectedPaths(final SQLRow r) {
212
        return this.getAffected(r, new ListMap<Path, ListSQLLine>(), false);
217
        final ListMap<Path, ListSQLLine> res = new ListMap<>();
-
 
218
        this.getAffected(r, res::add);
-
 
219
        return res;
213
    }
220
    }
214
 
221
 
215
    // must be called from within this queue, as this method use fullList
222
    // must be called from within this queue, as this method use fullList
216
    private <K, V> ListMap<K, V> getAffected(final SQLRow r, final ListMap<K, V> res, final boolean byLine) {
223
    private void getAffected(final SQLRow r, final BiConsumer<Path, ListSQLLine> cons) {
217
        final List<ListSQLLine> fullList = this.getFullList();
224
        final List<ListSQLLine> fullList = this.getFullList();
218
        synchronized (fullList) {
225
        synchronized (fullList) {
219
            final SQLTable t = r.getTable();
226
            final SQLTable t = r.getTable();
220
            final int id = r.getID();
227
            final int id = r.getID();
221
            if (id < SQLRow.MIN_VALID_ID)
228
            if (id < SQLRow.MIN_VALID_ID)
222
                throw new IllegalArgumentException("invalid ID: " + id);
229
                throw new IllegalArgumentException("invalid ID: " + id);
223
            if (!fullList.isEmpty()) {
230
            if (!fullList.isEmpty()) {
-
 
231
                final boolean keepGraph = this.getModel().getReq().getKeepMode() == KeepMode.GRAPH;
224
                final SQLRowValues proto = this.getState().getReq().getGraphToFetch();
232
                final SQLRowValues proto = this.getState().getReq().getGraphToFetch();
225
                final List<Path> pathsToT = new ArrayList<Path>();
233
                final List<Path> pathsToT = new ArrayList<Path>();
226
                proto.getGraph().walk(proto, pathsToT, new ITransformer<State<List<Path>>, List<Path>>() {
234
                proto.getGraph().walk(proto, pathsToT, new ITransformer<State<List<Path>>, List<Path>>() {
227
                    @Override
235
                    @Override
228
                    public List<Path> transformChecked(State<List<Path>> input) {
236
                    public List<Path> transformChecked(State<List<Path>> input) {
Line 230... Line 238...
230
                            input.getAcc().add(input.getPath());
238
                            input.getAcc().add(input.getPath());
231
                        }
239
                        }
232
                        return input.getAcc();
240
                        return input.getAcc();
233
                    }
241
                    }
234
                }, RecursionType.BREADTH_FIRST, Direction.ANY);
242
                }, RecursionType.BREADTH_FIRST, Direction.ANY);
-
 
243
                // paths aren't stored when !keepGraph
-
 
244
                if (!keepGraph) {
-
 
245
                    final RowRef idRef = r.getRowRef();
-
 
246
                    for (final ListSQLLine line : fullList) {
-
 
247
                        if (line.getPKs().contains(idRef))
-
 
248
                            cons.accept(null, line);
-
 
249
                    }
-
 
250
                }
235
                for (final Path p : pathsToT) {
251
                for (final Path p : pathsToT) {
236
                    final String lastReferentField = SearchQueue.getLastReferentField(p);
252
                    final String lastReferentField = SearchQueue.getLastReferentField(p);
-
 
253
                    final RowRef foreignRef;
-
 
254
                    if (lastReferentField != null && r.exists()) {
-
 
255
                        final SQLRowAccessor foreign = r.getNonEmptyForeign(lastReferentField);
-
 
256
                        foreignRef = foreign != null ? foreign.getRowRef() : null;
-
 
257
                    } else {
-
 
258
                        foreignRef = null;
-
 
259
                    }
-
 
260
                    // fullList already checked above, so if there's no foreignRef, there's nothing
-
 
261
                    // to do
-
 
262
                    if (!keepGraph && foreignRef == null)
-
 
263
                        continue;
237
                    for (final ListSQLLine line : fullList) {
264
                    for (final ListSQLLine line : fullList) {
238
                        boolean put = false;
265
                        boolean put = false;
-
 
266
                        if (keepGraph) {
239
                        for (final SQLRowValues current : line.getRow().followPath(p, CreateMode.CREATE_NONE, false)) {
267
                            for (final SQLRowValues current : line.getRow().getDistantRows(p)) {
240
                            // works for rowValues w/o any ID
268
                                // works for rowValues w/o any ID
241
                            if (current != null && current.getID() == id) {
269
                                if (current != null && current.getID() == id) {
242
                                put = true;
270
                                    put = true;
243
                            }
271
                                }
244
                        }
272
                            }
-
 
273
                        }
-
 
274
                        /*
245
                        // if the modified row isn't in the existing line, it might still affect it
275
                         * If the modified row isn't in the existing line, it might still affect it
246
                        // if it's a referent row insertion
276
                         * if it's a referent row insertion (a referent row update or deletion would
247
                        if (!put && lastReferentField != null && r.exists() && !r.isForeignEmpty(lastReferentField)) {
277
                         * mean than the current line contains the modified row and so "put" would
248
                            // no NPE, even without an undefined ID since we tested isForeignEmpty()
278
                         * already be true).
-
 
279
                         */
249
                            final int foreignID = r.getInt(lastReferentField);
280
                        if (!put && foreignRef != null) {
-
 
281
                            if (keepGraph) {
250
                            for (final SQLRowValues current : line.getRow().followPath(p.minusLast(), CreateMode.CREATE_NONE, false)) {
282
                                for (final SQLRowValues current : line.getRow().getDistantRows(p.minusLast())) {
251
                                if (current.getID() == foreignID) {
283
                                    if (current.getID() == foreignRef.getID().intValue()) {
252
                                    put = true;
284
                                        put = true;
253
                                }
285
                                    }
254
                            }
286
                                }
-
 
287
                            } else {
-
 
288
                                put = line.getPKs().contains(foreignRef);
-
 
289
                            }
255
                        }
290
                        }
256
                        if (put) {
291
                        if (put) {
257
                            // add to the list of paths that have been refreshed
292
                            // add to the list of paths that have been refreshed
258
                            add(byLine, res, p, line);
293
                            cons.accept(p, line);
259
                        }
294
                        }
260
                    }
295
                    }
261
                }
296
                }
262
            }
297
            }
263
        }
298
        }
264
        return res;
-
 
265
    }
-
 
266
 
-
 
267
    @SuppressWarnings("unchecked")
-
 
268
    <V, K> void add(boolean byLine, ListMap<K, V> res, final Path p, final ListSQLLine line) {
-
 
269
        if (byLine)
-
 
270
            res.add((K) line, (V) p);
-
 
271
        else
-
 
272
            res.add((K) p, (V) line);
-
 
273
    }
299
    }
274
 
300
 
275
    final void setFullList(final List<ListSQLLine> tmp, final SQLTableModelColumns cols) {
301
    final void setFullList(final List<ListSQLLine> tmp, final SQLTableModelColumns cols) {
276
        final List<ListSQLLine> fullList = this.getFullList();
302
        final List<ListSQLLine> fullList = this.getFullList();
277
        synchronized (fullList) {
303
        synchronized (fullList) {