OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | 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.view.list;
15
 
16
import org.openconcerto.sql.Log;
17
import org.openconcerto.sql.model.SQLRow;
18
import org.openconcerto.sql.model.SQLRowValues;
73 ilm 19
import org.openconcerto.sql.model.SQLRowValues.CreateMode;
17 ilm 20
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
21
import org.openconcerto.sql.model.SQLSelect;
22
import org.openconcerto.sql.model.graph.Path;
20 ilm 23
import org.openconcerto.sql.request.BaseFillSQLRequest;
17 ilm 24
import org.openconcerto.sql.request.ListSQLRequest;
73 ilm 25
import org.openconcerto.sql.view.list.search.SearchQueue;
26
import org.openconcerto.utils.CollectionUtils;
83 ilm 27
import org.openconcerto.utils.ListMap;
93 ilm 28
import org.openconcerto.utils.Value;
17 ilm 29
import org.openconcerto.utils.cc.ITransformer;
30
 
31
import java.util.Collection;
182 ilm 32
import java.util.HashSet;
17 ilm 33
import java.util.List;
34
import java.util.Map.Entry;
182 ilm 35
import java.util.Set;
17 ilm 36
 
37
abstract class AbstractUpdateOneRunnable extends UpdateRunnable {
38
 
73 ilm 39
    public AbstractUpdateOneRunnable(ITableModel model, final SQLRow r) {
40
        super(model, r);
17 ilm 41
        if (this.getID() < SQLRow.MIN_VALID_ID)
42
            throw new IllegalArgumentException("id is not valid : " + this.getID());
43
    }
44
 
83 ilm 45
    protected final ListMap<Path, ListSQLLine> getAffectedPaths() {
93 ilm 46
        return this.getUpdateQ().getAffectedPaths(this.getRow());
17 ilm 47
    }
48
 
83 ilm 49
    protected final void updateLines(ListMap<Path, ListSQLLine> paths) {
93 ilm 50
        this.updateLines(paths, Value.<ListSQLLine> getNone());
51
    }
52
 
53
    protected final void updateLines(ListMap<Path, ListSQLLine> paths, final Value<ListSQLLine> line) {
54
        final List<ListSQLLine> fullList = this.getUpdateQ().getFullList();
55
        synchronized (fullList) {
56
            this._updateLines(paths, line);
57
        }
58
    }
59
 
60
    private final void _updateLines(ListMap<Path, ListSQLLine> paths, final Value<ListSQLLine> newLine) {
61
        final boolean isPrimaryTable = getRow().getTable() == getReq().getParent().getPrimaryTable();
62
        // if we're refreshing the primary table, the new line must be provided
63
        assert newLine.hasValue() == isPrimaryTable;
64
        // even if paths is empty we might have to add a line, so this must be done outside the for
65
        if (isPrimaryTable) {
66
            final List<ListSQLLine> lines = paths.getNonNull(new Path(getRow().getTable()));
67
            if (lines.size() > 1)
68
                throw new IllegalStateException("More than one line for " + this.getRow() + " : " + lines);
69
            if (!newLine.hasValue())
70
                throw new IllegalArgumentException("Missing line");
71
            // update fullList
72
            final ListSQLLine oldLine = this.getUpdateQ().replaceLine(getRow().getID(), newLine.getValue());
73
            assert oldLine == CollectionUtils.getSole(lines);
74
        }
83 ilm 75
        for (final Entry<Path, ? extends Collection<ListSQLLine>> e : paths.entrySet()) {
17 ilm 76
            // eg SITE.ID_CONTACT_CHEF
77
            final Path p = e.getKey();
78
            // eg [SQLRowValues(SITE), SQLRowValues(SITE)]
79
            final List<ListSQLLine> lines = (List<ListSQLLine>) e.getValue();
93 ilm 80
            // primary table already handled above
81
            if (p.length() > 0 && !lines.isEmpty()) {
142 ilm 82
                final ListSQLRequest updateQueueReq = getModel().getLinesSource().getUpdateQueueReq();
17 ilm 83
                // deepCopy() instead of new SQLRowValues() otherwise the used line's graph will be
84
                // modified (eg the new instance would be linked to it)
142 ilm 85
                final SQLRowValues proto = updateQueueReq.getGraphToFetch().followPathToOne(p, CreateMode.CREATE_NONE, false).deepCopy();
73 ilm 86
                final String lastReferentField = SearchQueue.getLastReferentField(p);
87
                // there's only one path from the graph start to proto, and we will graft the newly
88
                // fetched values at the end of p, so remove other values
89
                if (lastReferentField != null) {
90
                    proto.put(lastReferentField, null);
91
                } else {
92
                    proto.clearReferents();
93
                    // keep only what has changed, eg CONTACT.NOM
94
                    proto.retainAll(getModifedFields());
95
                }
80 ilm 96
                // the modified fields aren't used at the path (e.g. if we display a row and its
97
                // same-table origin, the event was added by UpdateQueue.rowModified() since the
98
                // the modified fields are displayed for the primary row, but might not for the
99
                // origin)
100
                if (!proto.getFields().isEmpty()) {
101
                    // fetch the changed rowValues
102
                    // ATTN this doesn't use the original fetcher that was used in the updateAll
103
                    // MAYBE add a slower but accurate mode using the updateAll fetcher (and thus
104
                    // reloading rows from the primary table and not just the changed rows)
105
                    final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(proto);
106
                    BaseFillSQLRequest.setupForeign(fetcher);
142 ilm 107
                    if (updateQueueReq.isLockSelect()) {
108
                        fetcher.appendSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
109
                            @Override
110
                            public SQLSelect transformChecked(SQLSelect input) {
132 ilm 111
                                input.addLockedTable(getTable().getName());
142 ilm 112
                                return input;
113
                            }
114
                        });
115
                    }
116
                    final SQLRowValues soleFetched = fetcher.fetchOne(getRow().getIDNumber());
17 ilm 117
 
80 ilm 118
                    // OK if lastReferentField != null : a referent row has been deleted
142 ilm 119
                    if (soleFetched == null && lastReferentField == null) {
80 ilm 120
                        Log.get().fine("no row fetched for " + this + ", lines have been changed without the TableModel knowing : " + lines + " req :\n" + fetcher.getReq());
121
                        getModel().updateAll();
122
                    } else {
123
                        // copy it to each affected lines
124
                        for (final ListSQLLine line : lines) {
93 ilm 125
                            // don't update a part of the line, if the whole has been be passed to
126
                            // UpdateQueue.replaceLine()
127
                            // (if the primary table is in the graph more than once, and a row is
128
                            // deleted, the line might get (rightly) removed from the full list and
129
                            // then searched and added to the table model by the following)
130
                            if (!isPrimaryTable || getRow().getID() != line.getID())
131
                                this.getUpdateQ().updateLine(line, p, getRow().getID(), soleFetched);
80 ilm 132
                        }
17 ilm 133
                    }
134
                }
135
            }
136
        }
137
    }
138
 
182 ilm 139
    protected final void updateLines(final Set<Integer> affectedLines, final Integer primaryID) {
140
        final Set<Integer> idsToFetch;
141
        if (primaryID != null && !affectedLines.contains(primaryID)) {
142
            idsToFetch = new HashSet<>(affectedLines);
143
            idsToFetch.add(primaryID);
144
        } else {
145
            idsToFetch = affectedLines;
146
        }
147
        final List<ListSQLLine> newLines = getModel().getLinesSource().get(idsToFetch);
148
 
149
        final Set<Integer> notUpdated = new HashSet<>(affectedLines);
150
        synchronized (this.getUpdateQ().getFullList()) {
151
            for (final ListSQLLine newLine : newLines) {
152
                this.getUpdateQ().replaceLine(newLine.getID(), newLine);
153
                notUpdated.remove(newLine.getID());
154
            }
155
            for (final Integer toRemove : notUpdated) {
156
                this.getUpdateQ().replaceLine(toRemove, null);
157
            }
158
        }
159
    }
160
 
17 ilm 161
    protected abstract Collection<String> getModifedFields();
162
}