20
20
import java .text .MessageFormat ;
21
21
import java .util .ArrayList ;
22
22
import java .util .HashSet ;
23
- import java .util .LinkedList ;
24
23
import java .util .List ;
25
24
import java .util .Map ;
26
25
import java .util .Set ;
52
51
* @author Oliver Libutzki - Added reloadAllModelsOfType method
53
52
* @author Simon Kaufmann - added validation of models before loading them
54
53
* @author Laurent Garnier - Added method generateSyntaxFromModel
54
+ * @author Laurent Garnier - Added methods addStandaloneModel and removeStandaloneModel
55
55
*/
56
56
@ Component (immediate = true )
57
57
@ NonNullByDefault
@@ -100,17 +100,37 @@ public ModelRepositoryImpl(final @Reference SafeEMF safeEmf) {
100
100
101
101
@ Override
102
102
public boolean addOrRefreshModel (String name , final InputStream originalInputStream ) {
103
+ return addOrRefreshModel (name , originalInputStream , null , null , false );
104
+ }
105
+
106
+ public boolean addOrRefreshModel (String name , final InputStream originalInputStream , @ Nullable StringBuilder errors ,
107
+ @ Nullable StringBuilder warnings , boolean standalone ) {
103
108
logger .info ("Loading model '{}'" , name );
104
109
Resource resource = null ;
105
110
byte [] bytes ;
106
111
try (InputStream inputStream = originalInputStream ) {
107
112
bytes = inputStream .readAllBytes ();
108
- String validationResult = validateModel (name , new ByteArrayInputStream (bytes ));
109
- if (validationResult != null ) {
110
- logger .warn ("Configuration model '{}' has errors, therefore ignoring it: {}" , name , validationResult );
113
+ StringBuilder newErrors = new StringBuilder ();
114
+ StringBuilder newWarnings = new StringBuilder ();
115
+ boolean valid = validateModel (name , new ByteArrayInputStream (bytes ), newErrors , newWarnings );
116
+ if (errors != null ) {
117
+ errors .append (newErrors );
118
+ }
119
+ if (warnings != null ) {
120
+ warnings .append (newWarnings );
121
+ }
122
+ if (!valid ) {
123
+ if (!standalone ) {
124
+ logger .warn ("Configuration model '{}' has errors, therefore ignoring it: {}" , name ,
125
+ newErrors .toString ());
126
+ }
111
127
removeModel (name );
112
128
return false ;
113
129
}
130
+ String message = newWarnings .toString ();
131
+ if (!standalone && !message .isEmpty ()) {
132
+ logger .info ("Validation issues found in configuration model '{}', using it anyway:\n {}" , name , message );
133
+ }
114
134
} catch (IOException e ) {
115
135
logger .warn ("Configuration model '{}' cannot be parsed correctly!" , name , e );
116
136
return false ;
@@ -128,7 +148,9 @@ public boolean addOrRefreshModel(String name, final InputStream originalInputStr
128
148
resource = resourceSet .createResource (URI .createURI (name ));
129
149
if (resource != null ) {
130
150
resource .load (inputStream , resourceOptions );
131
- notifyListeners (name , EventType .ADDED );
151
+ if (!standalone ) {
152
+ notifyListeners (name , EventType .ADDED );
153
+ }
132
154
return true ;
133
155
} else {
134
156
logger .warn ("Ignoring file '{}' as we do not have a parser for it." , name );
@@ -139,7 +161,9 @@ public boolean addOrRefreshModel(String name, final InputStream originalInputStr
139
161
synchronized (resourceSet ) {
140
162
resource .unload ();
141
163
resource .load (inputStream , resourceOptions );
142
- notifyListeners (name , EventType .MODIFIED );
164
+ if (!standalone ) {
165
+ notifyListeners (name , EventType .MODIFIED );
166
+ }
143
167
return true ;
144
168
}
145
169
}
@@ -154,11 +178,17 @@ public boolean addOrRefreshModel(String name, final InputStream originalInputStr
154
178
155
179
@ Override
156
180
public boolean removeModel (String name ) {
181
+ return removeModel (name , false );
182
+ }
183
+
184
+ private boolean removeModel (String name , boolean standalone ) {
157
185
Resource resource = getResource (name );
158
186
if (resource != null ) {
159
187
synchronized (resourceSet ) {
160
188
// do not physically delete it, but remove it from the resource set
161
- notifyListeners (name , EventType .REMOVED );
189
+ if (!standalone ) {
190
+ notifyListeners (name , EventType .REMOVED );
191
+ }
162
192
resourceSet .getResources ().remove (resource );
163
193
return true ;
164
194
}
@@ -232,6 +262,18 @@ public void removeModelRepositoryChangeListener(ModelRepositoryChangeListener li
232
262
listeners .remove (listener );
233
263
}
234
264
265
+ @ Override
266
+ public @ Nullable String addStandaloneModel (String modelType , InputStream inputStream , StringBuilder errors ,
267
+ StringBuilder warnings ) {
268
+ String name = "tmp_syntax_%d.%s" .formatted (++counter , modelType );
269
+ return addOrRefreshModel (name , inputStream , errors , warnings , true ) ? name : null ;
270
+ }
271
+
272
+ @ Override
273
+ public boolean removeStandaloneModel (String name ) {
274
+ return removeModel (name , true );
275
+ }
276
+
235
277
@ Override
236
278
public void generateSyntaxFromModel (OutputStream out , String modelType , EObject modelContent ) {
237
279
String result = "" ;
@@ -269,40 +311,36 @@ public void generateSyntaxFromModel(OutputStream out, String modelType, EObject
269
311
* Validation will be done on a separate resource, in order to keep the original one intact in case its content
270
312
* needs to be removed because of syntactical errors.
271
313
*
272
- * @param name
273
- * @param inputStream
274
- * @return error messages as a String if any syntactical error were found, <code>null</code> otherwise
314
+ * @param name the model name
315
+ * @param inputStream an input stream with the model's content
316
+ * @param errors the string builder used to fill the errors
317
+ * @param warnings the string builder used to fill the warnings
318
+ * @return false if any syntactical error were found, false otherwise
275
319
* @throws IOException if there was an error with the given {@link InputStream}, loading the resource from there
276
320
*/
277
- private @ Nullable String validateModel (String name , InputStream inputStream ) throws IOException {
321
+ private boolean validateModel (String name , InputStream inputStream , StringBuilder errors , StringBuilder warnings )
322
+ throws IOException {
278
323
// use another resource for validation in order to keep the original one for emergency-removal in case of errors
279
324
Resource resource = resourceSet .createResource (URI .createURI ("tmp_" + name ));
280
325
try {
281
326
resource .load (inputStream , resourceOptions );
282
- StringBuilder criticalErrors = new StringBuilder ();
283
- List <String > warnings = new LinkedList <>();
284
327
285
328
if (!resource .getContents ().isEmpty ()) {
286
329
// Check for syntactical errors
287
330
for (Diagnostic diagnostic : resource .getErrors ()) {
288
- criticalErrors
289
- .append (MessageFormat .format ("[{0},{1}]: {2}\n " , Integer .toString (diagnostic .getLine ()),
290
- Integer .toString (diagnostic .getColumn ()), diagnostic .getMessage ()));
331
+ errors .append (MessageFormat .format ("[{0},{1}]: {2}\n " , Integer .toString (diagnostic .getLine ()),
332
+ Integer .toString (diagnostic .getColumn ()), diagnostic .getMessage ()));
291
333
}
292
- if (!criticalErrors .isEmpty ()) {
293
- return criticalErrors . toString () ;
334
+ if (!resource . getErrors () .isEmpty ()) {
335
+ return false ;
294
336
}
295
337
296
338
// Check for validation errors, but log them only
297
339
try {
298
340
final org .eclipse .emf .common .util .Diagnostic diagnostic = safeEmf
299
341
.call (() -> Diagnostician .INSTANCE .validate (resource .getContents ().getFirst ()));
300
342
for (org .eclipse .emf .common .util .Diagnostic d : diagnostic .getChildren ()) {
301
- warnings .add (d .getMessage ());
302
- }
303
- if (!warnings .isEmpty ()) {
304
- logger .info ("Validation issues found in configuration model '{}', using it anyway:\n {}" , name ,
305
- String .join ("\n " , warnings ));
343
+ warnings .append (d .getMessage () + "\n " );
306
344
}
307
345
} catch (NullPointerException e ) {
308
346
// see https://github.com/eclipse/smarthome/issues/3335
@@ -312,7 +350,7 @@ public void generateSyntaxFromModel(OutputStream out, String modelType, EObject
312
350
} finally {
313
351
resourceSet .getResources ().remove (resource );
314
352
}
315
- return null ;
353
+ return true ;
316
354
}
317
355
318
356
private void notifyListeners (String name , EventType type ) {
0 commit comments