OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 18 | Rev 61 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 18 Rev 25
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 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.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.erp.modules;
14
 package org.openconcerto.erp.modules;
15
 
15
 
-
 
16
import org.openconcerto.sql.model.DBRoot;
-
 
17
import org.openconcerto.sql.preferences.SQLPreferences;
16
import org.openconcerto.utils.cc.IPredicate;
18
import org.openconcerto.utils.cc.IPredicate;
17
 
19
 
18
import java.io.IOException;
20
import java.io.IOException;
19
import java.io.InputStream;
21
import java.io.InputStream;
20
import java.util.Collection;
22
import java.util.Collection;
21
import java.util.HashMap;
23
import java.util.HashMap;
22
import java.util.Locale;
24
import java.util.Locale;
23
import java.util.Map;
25
import java.util.Map;
24
import java.util.Properties;
26
import java.util.Properties;
25
import java.util.ResourceBundle;
27
import java.util.ResourceBundle;
-
 
28
import java.util.prefs.Preferences;
26
import java.util.regex.Matcher;
29
import java.util.regex.Matcher;
27
import java.util.regex.Pattern;
30
import java.util.regex.Pattern;
28
 
31
 
29
/**
32
/**
30
 * Parse module properties, and allow to create modules.
33
 * Parse module properties, and allow to create modules.
31
 * 
34
 * 
32
 * @author Sylvain CUAZ
35
 * @author Sylvain CUAZ
33
 */
36
 */
34
public abstract class ModuleFactory {
37
public abstract class ModuleFactory {
35
 
38
 
36
    public static final String NAME_KEY = "name";
39
    public static final String NAME_KEY = "name";
37
    public static final String DESC_KEY = "description";
40
    public static final String DESC_KEY = "description";
38
 
41
 
39
    protected static Properties readAndClose(final InputStream ins) throws IOException {
42
    protected static Properties readAndClose(final InputStream ins) throws IOException {
40
        final Properties props = new Properties();
43
        final Properties props = new Properties();
41
        try {
44
        try {
42
            props.load(ins);
45
            props.load(ins);
43
        } finally {
46
        } finally {
44
            ins.close();
47
            ins.close();
45
        }
48
        }
46
        return props;
49
        return props;
47
    }
50
    }
48
 
51
 
49
    protected static final String getRequiredProp(Properties props, final String key) {
52
    protected static final String getRequiredProp(Properties props, final String key) {
50
        final String res = props.getProperty(key);
53
        final String res = props.getProperty(key);
51
        if (res == null)
54
        if (res == null)
52
            throw new IllegalStateException("Missing " + key);
55
            throw new IllegalStateException("Missing " + key);
53
        return res;
56
        return res;
54
    }
57
    }
55
 
58
 
56
    private static String checkMatch(final Pattern p, final String s, final String name) {
59
    private static String checkMatch(final Pattern p, final String s, final String name) {
57
        if (!p.matcher(s).matches())
60
        if (!p.matcher(s).matches())
58
            throw new IllegalArgumentException(name + " doesn't match " + p.pattern());
61
            throw new IllegalArgumentException(name + " doesn't match " + p.pattern());
59
        return s;
62
        return s;
60
    }
63
    }
61
 
64
 
62
    private static final int parseInt(Matcher m, int group) {
65
    private static final int parseInt(Matcher m, int group) {
63
        final String s = m.group(group);
66
        final String s = m.group(group);
64
        return s == null ? 0 : Integer.parseInt(s);
67
        return s == null ? 0 : Integer.parseInt(s);
65
    }
68
    }
66
 
69
 
67
    private static final ModuleVersion getVersion(Matcher m, int offset) {
70
    private static final ModuleVersion getVersion(Matcher m, int offset) {
68
        return new ModuleVersion(parseInt(m, offset + 1), parseInt(m, offset + 2));
71
        return new ModuleVersion(parseInt(m, offset + 1), parseInt(m, offset + 2));
69
    }
72
    }
70
 
73
 
71
    private static final Pattern javaIdentifiedPatrn = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*");
74
    private static final Pattern javaIdentifiedPatrn = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*");
72
    private static final Pattern qualifiedPatrn = Pattern.compile(javaIdentifiedPatrn.pattern() + "(\\." + javaIdentifiedPatrn.pattern() + ")*");
75
    private static final Pattern qualifiedPatrn = Pattern.compile(javaIdentifiedPatrn.pattern() + "(\\." + javaIdentifiedPatrn.pattern() + ")*");
73
 
76
 
74
    private static final Pattern idPatrn = qualifiedPatrn;
77
    private static final Pattern idPatrn = qualifiedPatrn;
75
    // \1 major version, \2 minor version
78
    // \1 major version, \2 minor version
76
    private static final Pattern versionPatrn = Pattern.compile("(\\p{Digit}+)(?:\\.(\\p{Digit}+))?");
79
    private static final Pattern versionPatrn = Pattern.compile("(\\p{Digit}+)(?:\\.(\\p{Digit}+))?");
77
    private static final Pattern dependsSplitPatrn = Pattern.compile("\\p{Blank}*,\\p{Blank}+");
80
    private static final Pattern dependsSplitPatrn = Pattern.compile("\\p{Blank}*,\\p{Blank}+");
78
    // \1 id, \2 version
81
    // \1 id, \2 version
79
    private static final Pattern dependsPatrn = Pattern.compile("(" + idPatrn.pattern() + ")(?:\\p{Blank}+\\( *(" + versionPatrn.pattern() + ") *\\))?");
82
    private static final Pattern dependsPatrn = Pattern.compile("(" + idPatrn.pattern() + ")(?:\\p{Blank}+\\( *(" + versionPatrn.pattern() + ") *\\))?");
80
 
83
 
81
    private final String id;
84
    private final String id;
82
    private final ModuleVersion version;
85
    private final ModuleVersion version;
83
    // TODO add moduleAPIVersion;
86
    // TODO add moduleAPIVersion;
84
    private final String contact;
87
    private final String contact;
85
    private final Map<String, IPredicate<ModuleFactory>> dependsPredicates;
88
    private final Map<String, IPredicate<ModuleFactory>> dependsPredicates;
86
    private final String mainClass;
89
    private final String mainClass;
87
    private ResourceBundle rsrcBundle;
90
    private ResourceBundle rsrcBundle;
88
 
91
 
89
    protected ModuleFactory(final Properties props) throws IOException {
92
    protected ModuleFactory(final Properties props) throws IOException {
90
        this.id = checkMatch(idPatrn, getRequiredProp(props, "id").trim(), "ID");
93
        this.id = checkMatch(idPatrn, getRequiredProp(props, "id").trim(), "ID");
91
 
94
 
92
        final String version = getRequiredProp(props, "version").trim();
95
        final String version = getRequiredProp(props, "version").trim();
93
        final Matcher versionMatcher = versionPatrn.matcher(version);
96
        final Matcher versionMatcher = versionPatrn.matcher(version);
94
        if (!versionMatcher.matches())
97
        if (!versionMatcher.matches())
95
            throw new IllegalArgumentException("Version doesn't match " + versionPatrn.pattern());
98
            throw new IllegalArgumentException("Version doesn't match " + versionPatrn.pattern());
96
        this.version = getVersion(versionMatcher, 0);
99
        this.version = getVersion(versionMatcher, 0);
97
 
100
 
98
        this.contact = getRequiredProp(props, "contact");
101
        this.contact = getRequiredProp(props, "contact");
99
        final String depends = props.getProperty("depends", "").trim();
102
        final String depends = props.getProperty("depends", "").trim();
100
        final String[] dependsArray = depends.length() == 0 ? new String[0] : dependsSplitPatrn.split(depends);
103
        final String[] dependsArray = depends.length() == 0 ? new String[0] : dependsSplitPatrn.split(depends);
101
        this.dependsPredicates = new HashMap<String, IPredicate<ModuleFactory>>(dependsArray.length);
104
        this.dependsPredicates = new HashMap<String, IPredicate<ModuleFactory>>(dependsArray.length);
102
        for (final String depend : dependsArray) {
105
        for (final String depend : dependsArray) {
103
            final Matcher dependMatcher = dependsPatrn.matcher(depend);
106
            final Matcher dependMatcher = dependsPatrn.matcher(depend);
104
            if (!dependMatcher.matches())
107
            if (!dependMatcher.matches())
105
                throw new IllegalArgumentException("'" + depend + "' doesn't match " + dependsPatrn.pattern());
108
                throw new IllegalArgumentException("'" + depend + "' doesn't match " + dependsPatrn.pattern());
106
            final ModuleVersion depVersion = getVersion(dependMatcher, 2);
109
            final ModuleVersion depVersion = getVersion(dependMatcher, 2);
107
            this.dependsPredicates.put(dependMatcher.group(1), new IPredicate<ModuleFactory>() {
110
            this.dependsPredicates.put(dependMatcher.group(1), new IPredicate<ModuleFactory>() {
108
                @Override
111
                @Override
109
                public boolean evaluateChecked(ModuleFactory input) {
112
                public boolean evaluateChecked(ModuleFactory input) {
110
                    return input.getVersion().compareTo(depVersion) >= 0;
113
                    return input.getVersion().compareTo(depVersion) >= 0;
111
                }
114
                }
112
            });
115
            });
113
        }
116
        }
114
 
117
 
115
        final String entryPoint = checkMatch(javaIdentifiedPatrn, props.getProperty("entryPoint", "Module"), "Entry point");
118
        final String entryPoint = checkMatch(javaIdentifiedPatrn, props.getProperty("entryPoint", "Module"), "Entry point");
116
        this.mainClass = this.id + "." + entryPoint;
119
        this.mainClass = this.id + "." + entryPoint;
117
 
120
 
118
        this.rsrcBundle = null;
121
        this.rsrcBundle = null;
119
    }
122
    }
120
 
123
 
121
    public final String getID() {
124
    public final String getID() {
122
        return this.id;
125
        return this.id;
123
    }
126
    }
124
 
127
 
125
    public final String getContact() {
128
    public final String getContact() {
126
        return this.contact;
129
        return this.contact;
127
    }
130
    }
128
 
131
 
129
    public final ModuleVersion getVersion() {
132
    public final ModuleVersion getVersion() {
130
        return this.version;
133
        return this.version;
131
    }
134
    }
132
 
135
 
133
    public final int getMajorVersion() {
136
    public final int getMajorVersion() {
134
        return this.version.getMajor();
137
        return this.version.getMajor();
135
    }
138
    }
136
 
139
 
137
    public final int getMinorVersion() {
140
    public final int getMinorVersion() {
138
        return this.version.getMinor();
141
        return this.version.getMinor();
139
    }
142
    }
140
 
143
 
141
    protected final String getMainClass() {
144
    protected final String getMainClass() {
142
        return this.mainClass;
145
        return this.mainClass;
143
    }
146
    }
144
 
147
 
145
    public final Collection<String> getRequiredIDs() {
148
    public final Collection<String> getRequiredIDs() {
146
        return this.dependsPredicates.keySet();
149
        return this.dependsPredicates.keySet();
147
    }
150
    }
148
 
151
 
149
    public final boolean isRequiredFactoryOK(ModuleFactory f) {
152
    public final boolean isRequiredFactoryOK(ModuleFactory f) {
150
        return this.dependsPredicates.get(f.getID()).evaluateChecked(f);
153
        return this.dependsPredicates.get(f.getID()).evaluateChecked(f);
151
    }
154
    }
152
 
155
 
153
    protected final ResourceBundle getResourceBundle() {
156
    protected final ResourceBundle getResourceBundle() {
154
        if (this.rsrcBundle == null) {
157
        if (this.rsrcBundle == null) {
155
            // don't allow classes to simplify class loaders
158
            // don't allow classes to simplify class loaders
156
            this.rsrcBundle = ResourceBundle.getBundle(getID() + ".ModuleResources", Locale.getDefault(), getRsrcClassLoader(),
159
            this.rsrcBundle = ResourceBundle.getBundle(getID() + ".ModuleResources", Locale.getDefault(), getRsrcClassLoader(),
157
                    ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES));
160
                    ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES));
158
        }
161
        }
159
        return this.rsrcBundle;
162
        return this.rsrcBundle;
160
    }
163
    }
161
 
164
 
162
    protected abstract ClassLoader getRsrcClassLoader();
165
    protected abstract ClassLoader getRsrcClassLoader();
163
 
166
 
164
    public final String getName() {
167
    public final String getName() {
165
        return this.getResourceBundle().getString(NAME_KEY);
168
        return this.getResourceBundle().getString(NAME_KEY);
166
    }
169
    }
167
 
170
 
168
    public final String getDescription() {
171
    public final String getDescription() {
169
        return this.getResourceBundle().getString(DESC_KEY);
172
        return this.getResourceBundle().getString(DESC_KEY);
170
    }
173
    }
171
 
174
 
172
    public abstract AbstractModule createModule(Map<String, AbstractModule> alreadyCreated) throws Exception;
175
    public abstract AbstractModule createModule(Map<String, AbstractModule> alreadyCreated) throws Exception;
173
 
176
 
174
    protected final AbstractModule createModule(final Class<?> c) throws Exception {
177
    protected final AbstractModule createModule(final Class<?> c) throws Exception {
175
        return (AbstractModule) c.getConstructor(ModuleFactory.class).newInstance(this);
178
        return (AbstractModule) c.getConstructor(ModuleFactory.class).newInstance(this);
176
    }
179
    }
177
 
180
 
-
 
181
    public final Preferences getLocalPreferences() {
-
 
182
        return this.getPreferences(true, null);
-
 
183
    }
-
 
184
 
-
 
185
    public final Preferences getSQLPreferences(final DBRoot root) {
-
 
186
        return this.getPreferences(false, root);
-
 
187
    }
-
 
188
 
-
 
189
    public final Preferences getPreferences(final boolean local, final DBRoot root) {
-
 
190
        final Preferences rootPrefs = local ? Preferences.userRoot() : new SQLPreferences(root);
-
 
191
        // ID is a package name, transform to path to avoid bumping into the size limit
-
 
192
        return rootPrefs.node(ModulePreferencePanel.getAppPrefPath() + this.getID().replace('.', '/'));
-
 
193
    }
-
 
194
 
178
    @Override
195
    @Override
179
    public String toString() {
196
    public String toString() {
180
        return super.toString() + " " + getID() + " (" + getMajorVersion() + "." + getMinorVersion() + ")";
197
        return getClass().getSimpleName() + " " + getID() + " (" + getMajorVersion() + "." + getMinorVersion() + ")";
181
    }
198
    }
182
}
199
}