OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 149 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
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.erp.modules;
15
 
80 ilm 16
import org.openconcerto.erp.config.Log;
19 ilm 17
 
80 ilm 18
import java.io.IOException;
19
import java.sql.SQLException;
18 ilm 20
import java.util.ArrayList;
21
import java.util.Collection;
19 ilm 22
import java.util.Collections;
23
import java.util.Comparator;
80 ilm 24
import java.util.EnumSet;
25
import java.util.HashMap;
19 ilm 26
import java.util.HashSet;
18 ilm 27
import java.util.List;
80 ilm 28
import java.util.Map;
29
import java.util.Map.Entry;
19 ilm 30
import java.util.Set;
80 ilm 31
import java.util.SortedMap;
32
import java.util.logging.Level;
18 ilm 33
 
34
import javax.swing.table.AbstractTableModel;
35
 
80 ilm 36
import net.jcip.annotations.Immutable;
37
 
18 ilm 38
public class ModuleTableModel extends AbstractTableModel {
39
 
81 ilm 40
    static public enum Problem {
41
        /**
42
         * The module is required but missing.
43
         */
44
        REQUIRED_MISSING,
45
        /**
46
         * The module is installed but lacks at least one dependency.
47
         */
48
        MISSING_DEP
49
    }
50
 
51
    // ref needed if factory is null
52
    static private final boolean areDepsMet(final ModuleFactory factory, final InstallationState installationState) {
53
        for (final Dependency dep : factory.getDependencies().values()) {
54
            boolean depMet = false;
55
            for (final String reqID : dep.getRequiredIDs()) {
56
                final ModuleFactory f = installationState.getInstalledFactories().get(reqID);
57
                if (f != null && dep.isRequiredFactoryOK(f)) {
58
                    depMet = true;
59
                    break;
60
                }
61
            }
62
            if (!depMet)
63
                return false;
64
        }
65
        return true;
66
    }
67
 
80 ilm 68
    @Immutable
69
    static final class ModuleRow {
70
        private final ModuleReference ref;
71
        private final ModuleFactory factory;
72
        private final boolean local, remote, registered, running;
73
        private final boolean dbRequired, adminRequired;
81 ilm 74
        private final Set<Problem> problems;
19 ilm 75
 
81 ilm 76
        public ModuleRow(ModuleReference ref, ModuleFactory f, InstallationState installationState, boolean registered, boolean running, boolean dbRequired, boolean adminRequired) {
80 ilm 77
            super();
78
            if (ref == null)
79
                throw new NullPointerException("Null reference");
80
            this.ref = ref;
81
            this.factory = f;
82
            assert this.factory == null || this.factory.getReference().equals(this.ref);
81 ilm 83
            this.local = installationState.getLocal().contains(ref);
84
            this.remote = installationState.getRemote().contains(ref);
80 ilm 85
            this.registered = registered;
86
            this.running = running;
87
            this.dbRequired = dbRequired;
88
            this.adminRequired = adminRequired;
81 ilm 89
            final Set<Problem> pbs = new HashSet<Problem>(Problem.values().length);
90
            final boolean isInstalled = this.isInstalledLocally() || this.isInstalledRemotely();
91
            if (!this.isAvailable() && isInstalled) {
92
                pbs.add(Problem.REQUIRED_MISSING);
93
            }
94
            // if installed and not available, we cannot know its dependencies but it will be marked
95
            // REQUIRED_MISSING
96
            if (this.isAvailable() && isInstalled && !areDepsMet(this.factory, installationState)) {
97
                pbs.add(Problem.MISSING_DEP);
98
            }
99
            this.problems = pbs.size() == 0 ? Collections.<Problem> emptySet() : Collections.unmodifiableSet(pbs);
80 ilm 100
        }
18 ilm 101
 
80 ilm 102
        public ModuleReference getRef() {
103
            return this.ref;
104
        }
105
 
106
        public final String getName() {
107
            return this.factory != null ? this.factory.getName() : this.getRef().getID();
108
        }
109
 
110
        public boolean isAvailable() {
111
            return this.factory != null;
112
        }
113
 
114
        public boolean isInstalledLocally() {
115
            return this.local;
116
        }
117
 
118
        public boolean isInstalledRemotely() {
119
            return this.remote;
120
        }
121
 
122
        public boolean isRegistered() {
123
            return this.registered;
124
        }
125
 
126
        public boolean isRunning() {
127
            return this.running;
128
        }
129
 
130
        public boolean isDBRequired() {
131
            return this.dbRequired;
132
        }
133
 
134
        public boolean isAdminRequired() {
135
            return this.adminRequired;
136
        }
137
 
81 ilm 138
        public Set<Problem> getProblems() {
139
            return this.problems;
140
        }
141
 
80 ilm 142
        @Override
143
        public int hashCode() {
144
            final int prime = 31;
145
            int result = 1;
146
            result = prime * result + this.ref.hashCode();
147
            return result;
148
        }
149
 
150
        @Override
151
        public boolean equals(Object obj) {
152
            if (this == obj)
153
                return true;
154
            if (obj == null)
155
                return false;
156
            if (getClass() != obj.getClass())
157
                return false;
158
            final ModuleRow other = (ModuleRow) obj;
159
            return this.ref.equals(other.ref);
160
        }
18 ilm 161
    }
162
 
80 ilm 163
    // TODO add DESC and ERROR
164
    static enum Columns {
165
        CB, NAME, VERSION, STATE, LOCAL, REMOTE, DB_REQUIRED, ADMIN_REQUIRED
166
    }
167
 
168
    static private final EnumSet<Columns> BOOLEAN_COLS = EnumSet.of(Columns.CB, Columns.LOCAL, Columns.REMOTE, Columns.DB_REQUIRED, Columns.ADMIN_REQUIRED);
169
 
156 ilm 170
    private final ModuleManager mngr;
80 ilm 171
    private List<ModuleRow> list;
172
    private final Set<ModuleRow> selection;
173
 
174
    private boolean valid;
175
 
156 ilm 176
    public ModuleTableModel(ModuleManager mngr) {
177
        this.mngr = mngr;
80 ilm 178
        this.selection = new HashSet<ModuleRow>();
179
        this.list = Collections.emptyList();
180
        this.valid = false;
181
    }
182
 
156 ilm 183
    public final ModuleManager getModuleManager() {
184
        return this.mngr;
185
    }
186
 
80 ilm 187
    final void clear() {
188
        this.selection.clear();
189
        this.list = Collections.emptyList();
190
        this.fireTableDataChanged();
191
    }
192
 
193
    public final void reload() throws IOException, SQLException {
156 ilm 194
        final ModuleManager mngr = this.getModuleManager();
80 ilm 195
        final InstallationState installationState = new InstallationState(mngr);
196
        final Map<ModuleReference, ModuleFactory> available = new HashMap<ModuleReference, ModuleFactory>();
197
        for (final Entry<String, SortedMap<ModuleVersion, ModuleFactory>> e : mngr.getFactories().entrySet()) {
198
            for (final Entry<ModuleVersion, ModuleFactory> e2 : e.getValue().entrySet()) {
199
                available.put(new ModuleReference(e.getKey(), e2.getKey()), e2.getValue());
200
            }
201
        }
202
        // we're reloading so sync preferences
203
        final List<ModuleReference> adminRequired = mngr.getAdminRequiredModules(true);
204
        final List<ModuleReference> dbRequired = mngr.getDBRequiredModules();
205
        final Set<ModuleReference> running = new HashSet<ModuleReference>();
206
        for (final Entry<String, AbstractModule> e : mngr.getRunningModules().entrySet()) {
207
            running.add(new ModuleReference(e.getKey(), e.getValue().getFactory().getVersion()));
208
        }
209
        final Collection<ModuleReference> registered = mngr.getRegisteredModules();
210
 
211
        // if some installed modules lack their factory, we cannot know if they conflict with
212
        // modules to install (see DepSolverResultMM.computeReferencesToRemove())
81 ilm 213
        this.valid = true;
80 ilm 214
 
215
        // all known references
216
        final Set<ModuleReference> s = new HashSet<ModuleReference>(installationState.getLocalOrRemote());
217
        s.addAll(available.keySet());
218
        final List<ModuleRow> l = new ArrayList<ModuleRow>(s.size());
219
        for (final ModuleReference ref : s) {
81 ilm 220
            final ModuleRow row = new ModuleRow(ref, available.get(ref), installationState, registered.contains(ref), running.contains(ref), dbRequired.contains(ref), adminRequired.contains(ref));
221
            l.add(row);
222
            this.valid &= row.getProblems().size() == 0;
80 ilm 223
        }
224
 
225
        // sort alphabetically and then highest version first
226
        Collections.sort(l, new Comparator<ModuleRow>() {
19 ilm 227
            @Override
80 ilm 228
            public int compare(ModuleRow r1, ModuleRow r2) {
229
                final ModuleReference o1 = r1.getRef();
230
                final ModuleReference o2 = r2.getRef();
231
                return ModuleReference.COMP_ID_ASC_VERSION_DESC.compare(o1, o2);
19 ilm 232
            }
233
        });
80 ilm 234
        this.list = Collections.unmodifiableList(l);
19 ilm 235
        this.selection.retainAll(this.list);
236
        this.fireTableDataChanged();
237
    }
238
 
80 ilm 239
    public final boolean isValid() {
240
        return this.valid;
241
    }
242
 
243
    public final Collection<ModuleRow> getCheckedRows() {
19 ilm 244
        return Collections.unmodifiableSet(this.selection);
245
    }
246
 
18 ilm 247
    @Override
248
    public int getColumnCount() {
80 ilm 249
        return Columns.values().length;
18 ilm 250
    }
251
 
252
    @Override
27 ilm 253
    public final int getRowCount() {
18 ilm 254
        return this.list.size();
255
    }
256
 
80 ilm 257
    protected final ModuleRow getFactory(int i) {
27 ilm 258
        return this.list.get(i);
259
    }
260
 
80 ilm 261
    protected final ModuleRow getRow(final ModuleReference ref) {
262
        if (ref.getVersion() == null)
263
            throw new IllegalStateException("Null version");
264
        for (final ModuleRow r : this.list) {
265
            if (r.getRef().equals(ref))
266
                return r;
267
        }
268
        return null;
269
    }
270
 
18 ilm 271
    @Override
272
    public boolean isCellEditable(int rowIndex, int columnIndex) {
80 ilm 273
        return columnIndex == Columns.CB.ordinal();
18 ilm 274
    }
275
 
276
    @Override
277
    public String getColumnName(int column) {
80 ilm 278
        final Columns col = Columns.values()[column];
279
        switch (col) {
280
        case NAME:
18 ilm 281
            return "Nom";
80 ilm 282
        case VERSION:
18 ilm 283
            return "Version";
80 ilm 284
        case STATE:
285
            return "Etat";
286
        case LOCAL:
287
            return "Installé sur le poste";
288
        case REMOTE:
289
            return "Installé sur le serveur";
290
        case DB_REQUIRED:
291
            return "Requis par le système";
292
        case ADMIN_REQUIRED:
293
            return "Requis par l'administrateur";
294
        default:
295
            return "";
18 ilm 296
        }
297
    }
298
 
299
    @Override
300
    public Object getValueAt(int rowIndex, int columnIndex) {
80 ilm 301
        final ModuleRow f = this.getFactory(rowIndex);
302
        final Columns col = Columns.values()[columnIndex];
303
        try {
304
            switch (col) {
305
            case CB:
306
                return this.selection.contains(f);
307
            case NAME:
308
                return f.getName();
309
            case VERSION:
310
                return f.getRef().getVersion();
311
            case STATE:
81 ilm 312
                final String s;
80 ilm 313
                if (f.isRunning())
81 ilm 314
                    s = "Démarré";
80 ilm 315
                else if (f.isRegistered())
81 ilm 316
                    s = "Chargé";
80 ilm 317
                else if (f.isAvailable())
81 ilm 318
                    s = "Disponible";
80 ilm 319
                else
81 ilm 320
                    s = "Non disponible";
321
                final Set<Problem> pbs = f.getProblems();
322
                if (pbs.size() == 0)
323
                    return s;
324
                final StringBuilder sb = new StringBuilder(64);
325
                sb.append("<html><body>");
326
                sb.append(s);
327
                // now add error tags
328
                // space at the end for background
329
                sb.append(" <font bgcolor=\"RED\" color=\"WHITE\">&nbsp;");
330
                if (pbs.contains(Problem.REQUIRED_MISSING))
331
                    sb.append("Module&nbsp;requis ");
332
                if (pbs.contains(Problem.MISSING_DEP))
333
                    sb.append("Dépendances&nbsp;manquantes ");
334
                // leave last space for background
335
                sb.append("</font></body></html>");
336
                return sb.toString();
80 ilm 337
            case LOCAL:
338
                return f.isInstalledLocally();
339
            case REMOTE:
340
                return f.isInstalledRemotely();
341
            case DB_REQUIRED:
342
                return f.isDBRequired();
343
            case ADMIN_REQUIRED:
344
                return f.isAdminRequired();
345
            default:
346
                return "";
19 ilm 347
            }
80 ilm 348
        } catch (Exception e) {
349
            Log.get().log(Level.SEVERE, "row:" + rowIndex + " column:" + columnIndex, e);
350
            return e.getMessage();
18 ilm 351
        }
352
    }
353
 
354
    @Override
355
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
80 ilm 356
        if (columnIndex == Columns.CB.ordinal()) {
19 ilm 357
            if ((Boolean) value)
80 ilm 358
                this.selection.add(this.getFactory(rowIndex));
19 ilm 359
            else
80 ilm 360
                this.selection.remove(this.getFactory(rowIndex));
18 ilm 361
        }
362
    }
363
 
364
    @Override
365
    public Class<?> getColumnClass(int columnIndex) {
80 ilm 366
        if (BOOLEAN_COLS.contains(Columns.values()[columnIndex])) {
18 ilm 367
            return Boolean.class;
149 ilm 368
        } else if (columnIndex == Columns.VERSION.ordinal()) {
369
            return ModuleVersion.class;
18 ilm 370
        } else {
371
            return String.class;
372
        }
373
    }
374
}