1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.helger.schematron.pure.model;
18
19 import java.util.Map;
20
21 import javax.annotation.Nonnegative;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import javax.annotation.concurrent.NotThreadSafe;
25
26 import com.helger.commons.ValueEnforcer;
27 import com.helger.commons.annotation.ReturnsMutableCopy;
28 import com.helger.commons.collection.CollectionHelper;
29 import com.helger.commons.collection.ext.CommonsArrayList;
30 import com.helger.commons.collection.ext.CommonsLinkedHashMap;
31 import com.helger.commons.collection.ext.ICommonsList;
32 import com.helger.commons.collection.ext.ICommonsOrderedMap;
33 import com.helger.commons.string.StringHelper;
34 import com.helger.commons.string.ToStringGenerator;
35 import com.helger.schematron.CSchematron;
36 import com.helger.schematron.CSchematronXML;
37 import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
38 import com.helger.xml.microdom.IMicroElement;
39 import com.helger.xml.microdom.MicroElement;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 @NotThreadSafe
149 public class PSPattern implements
150 IPSElement,
151 IPSHasID,
152 IPSHasForeignElements,
153 IPSHasIncludes,
154 IPSHasLets,
155 IPSHasRichGroup
156 {
157 private boolean m_bAbstract = false;
158 private String m_sID;
159 private String m_sIsA;
160 private PSRichGroup m_aRich;
161 private final ICommonsList <PSInclude> m_aIncludes = new CommonsArrayList <> ();
162 private PSTitle m_aTitle;
163 private final ICommonsList <IPSElement> m_aContent = new CommonsArrayList <> ();
164 private ICommonsOrderedMap <String, String> m_aForeignAttrs;
165 private ICommonsList <IMicroElement> m_aForeignElements;
166
167 public PSPattern ()
168 {}
169
170 public boolean isValid (@Nonnull final IPSErrorHandler aErrorHandler)
171 {
172
173 if (m_bAbstract && StringHelper.hasNoText (m_sID))
174 {
175 aErrorHandler.error (this, "abstract <pattern> does not have an 'id'");
176 return false;
177 }
178
179 if (m_bAbstract && StringHelper.hasText (m_sIsA))
180 {
181 aErrorHandler.error (this, "abstract <pattern> may not have an 'is-a'");
182 return false;
183 }
184 if (StringHelper.hasNoText (m_sIsA))
185 {
186
187 for (final IPSElement aContent : m_aContent)
188 if (aContent instanceof PSParam)
189 {
190 aErrorHandler.error (this, "<pattern> without 'is-a' may not contain <param>s");
191 return false;
192 }
193 }
194 else
195 {
196
197 for (final IPSElement aContent : m_aContent)
198 {
199 if (aContent instanceof PSRule)
200 {
201 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <rule>s");
202 return false;
203 }
204 if (aContent instanceof PSLet)
205 {
206 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <let>s");
207 return false;
208 }
209 }
210 }
211
212 for (final PSInclude aInclude : m_aIncludes)
213 if (!aInclude.isValid (aErrorHandler))
214 return false;
215 if (m_aTitle != null && !m_aTitle.isValid (aErrorHandler))
216 return false;
217 for (final IPSElement aContent : m_aContent)
218 if (!aContent.isValid (aErrorHandler))
219 return false;
220 return true;
221 }
222
223 public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
224 {
225
226 if (m_bAbstract && StringHelper.hasNoText (m_sID))
227 aErrorHandler.error (this, "abstract <pattern> does not have an 'id'");
228
229 if (m_bAbstract && StringHelper.hasText (m_sIsA))
230 aErrorHandler.error (this, "abstract <pattern> may not have an 'is-a'");
231 if (StringHelper.hasNoText (m_sIsA))
232 {
233
234 for (final IPSElement aContent : m_aContent)
235 if (aContent instanceof PSParam)
236 aErrorHandler.error (this, "<pattern> without 'is-a' may not contain <param>s");
237 }
238 else
239 {
240
241 for (final IPSElement aContent : m_aContent)
242 {
243 if (aContent instanceof PSRule)
244 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <rule>s");
245 if (aContent instanceof PSLet)
246 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <let>s");
247 }
248 }
249
250 for (final PSInclude aInclude : m_aIncludes)
251 aInclude.validateCompletely (aErrorHandler);
252 if (m_aTitle != null)
253 m_aTitle.validateCompletely (aErrorHandler);
254 for (final IPSElement aContent : m_aContent)
255 aContent.validateCompletely (aErrorHandler);
256 }
257
258 public boolean isMinimal ()
259 {
260 if (m_bAbstract)
261 return false;
262 if (StringHelper.hasText (m_sIsA))
263 return false;
264 for (final PSInclude aInclude : m_aIncludes)
265 if (!aInclude.isMinimal ())
266 return false;
267 if (m_aTitle != null && !m_aTitle.isMinimal ())
268 return false;
269 for (final IPSElement aContent : m_aContent)
270 if (!aContent.isMinimal ())
271 return false;
272 return true;
273 }
274
275 public void addForeignElement (@Nonnull final IMicroElement aForeignElement)
276 {
277 ValueEnforcer.notNull (aForeignElement, "ForeignElement");
278 if (aForeignElement.hasParent ())
279 throw new IllegalArgumentException ("ForeignElement already has a parent!");
280 if (m_aForeignElements == null)
281 m_aForeignElements = new CommonsArrayList <> ();
282 m_aForeignElements.add (aForeignElement);
283 }
284
285 public boolean hasForeignElements ()
286 {
287 return m_aForeignElements != null && m_aForeignElements.isNotEmpty ();
288 }
289
290 @Nonnull
291 @ReturnsMutableCopy
292 public ICommonsList <IMicroElement> getAllForeignElements ()
293 {
294 return new CommonsArrayList <> (m_aForeignElements);
295 }
296
297 public void addForeignAttribute (@Nonnull final String sAttrName, @Nonnull final String sAttrValue)
298 {
299 ValueEnforcer.notNull (sAttrName, "AttrName");
300 ValueEnforcer.notNull (sAttrValue, "AttrValue");
301 if (m_aForeignAttrs == null)
302 m_aForeignAttrs = new CommonsLinkedHashMap <> ();
303 m_aForeignAttrs.put (sAttrName, sAttrValue);
304 }
305
306 public boolean hasForeignAttributes ()
307 {
308 return m_aForeignAttrs != null && m_aForeignAttrs.isNotEmpty ();
309 }
310
311 @Nonnull
312 @ReturnsMutableCopy
313 public ICommonsOrderedMap <String, String> getAllForeignAttributes ()
314 {
315 return new CommonsLinkedHashMap <> (m_aForeignAttrs);
316 }
317
318 public void setAbstract (final boolean bAbstract)
319 {
320 m_bAbstract = bAbstract;
321 }
322
323 public boolean isAbstract ()
324 {
325 return m_bAbstract;
326 }
327
328 public void setID (@Nullable final String sID)
329 {
330 m_sID = sID;
331 }
332
333 @Nullable
334 public String getID ()
335 {
336 return m_sID;
337 }
338
339 public void setIsA (@Nullable final String sIsA)
340 {
341 m_sIsA = sIsA;
342 }
343
344 @Nullable
345 public String getIsA ()
346 {
347 return m_sIsA;
348 }
349
350 public void setRich (@Nullable final PSRichGroup aRich)
351 {
352 m_aRich = aRich;
353 }
354
355 @Nullable
356 public PSRichGroup getRich ()
357 {
358 return m_aRich;
359 }
360
361 public void addInclude (@Nonnull final PSInclude aInclude)
362 {
363 ValueEnforcer.notNull (aInclude, "Include");
364 m_aIncludes.add (aInclude);
365 }
366
367 public boolean hasAnyInclude ()
368 {
369 return m_aIncludes.isNotEmpty ();
370 }
371
372 @Nonnull
373 @ReturnsMutableCopy
374 public ICommonsList <PSInclude> getAllIncludes ()
375 {
376 return m_aIncludes.getClone ();
377 }
378
379 public void setTitle (@Nullable final PSTitle aTitle)
380 {
381 m_aTitle = aTitle;
382 }
383
384 @Nullable
385 public PSTitle getTitle ()
386 {
387 return m_aTitle;
388 }
389
390 public boolean hasTitle ()
391 {
392 return m_aTitle != null;
393 }
394
395 public void addRule (@Nonnull final PSRule aRule)
396 {
397 ValueEnforcer.notNull (aRule, "Rule");
398 m_aContent.add (aRule);
399 }
400
401 @Nullable
402 public PSRule getRuleOfID (@Nullable final String sID)
403 {
404 if (StringHelper.hasText (sID))
405 for (final IPSElement aElement : m_aContent)
406 if (aElement instanceof PSRule)
407 {
408 final PSRule aRule = (PSRule) aElement;
409 if (sID.equals (aRule.getID ()))
410 return aRule;
411 }
412 return null;
413 }
414
415 @Nonnull
416 @ReturnsMutableCopy
417 public ICommonsList <PSRule> getAllRules ()
418 {
419 return m_aContent.getAllInstanceOf (PSRule.class);
420 }
421
422 @Nonnegative
423 public int getRuleCount ()
424 {
425 return m_aContent.getCount (e -> e instanceof PSRule);
426 }
427
428 public void addParam (@Nonnull final PSParam aParam)
429 {
430 ValueEnforcer.notNull (aParam, "Param");
431 m_aContent.add (aParam);
432 }
433
434 @Nonnull
435 @ReturnsMutableCopy
436 public ICommonsList <PSParam> getAllParams ()
437 {
438 return m_aContent.getAllInstanceOf (PSParam.class);
439 }
440
441 public boolean hasAnyParam ()
442 {
443 return m_aContent.containsAny (e -> e instanceof PSParam);
444 }
445
446 public void addP (@Nonnull final PSP aP)
447 {
448 ValueEnforcer.notNull (aP, "P");
449 m_aContent.add (aP);
450 }
451
452 @Nonnull
453 @ReturnsMutableCopy
454 public ICommonsList <PSP> getAllPs ()
455 {
456 return m_aContent.getAllInstanceOf (PSP.class);
457 }
458
459 public void addLet (@Nonnull final PSLet aLet)
460 {
461 ValueEnforcer.notNull (aLet, "Let");
462 m_aContent.add (aLet);
463 }
464
465 public boolean hasAnyLet ()
466 {
467 return m_aContent.containsAny (e -> e instanceof PSLet);
468 }
469
470 @Nonnull
471 @ReturnsMutableCopy
472 public ICommonsList <PSLet> getAllLets ()
473 {
474 return m_aContent.getAllInstanceOf (PSLet.class);
475 }
476
477 @Nonnull
478 @ReturnsMutableCopy
479 public ICommonsOrderedMap <String, String> getAllLetsAsMap ()
480 {
481 final ICommonsOrderedMap <String, String> ret = new CommonsLinkedHashMap <> ();
482 for (final IPSElement aElement : m_aContent)
483 if (aElement instanceof PSLet)
484 {
485 final PSLet aLet = (PSLet) aElement;
486 ret.put (aLet.getName (), aLet.getValue ());
487 }
488 return ret;
489 }
490
491
492
493
494
495 @Nonnull
496 @ReturnsMutableCopy
497 public ICommonsList <IPSElement> getAllContentElements ()
498 {
499 return m_aContent.getClone ();
500 }
501
502 @Nonnull
503 public IMicroElement getAsMicroElement ()
504 {
505 final IMicroElement ret = new MicroElement (CSchematron.NAMESPACE_SCHEMATRON, CSchematronXML.ELEMENT_PATTERN);
506 if (m_bAbstract)
507 ret.setAttribute (CSchematronXML.ATTR_ABSTRACT, "true");
508 ret.setAttribute (CSchematronXML.ATTR_ID, m_sID);
509 ret.setAttribute (CSchematronXML.ATTR_IS_A, m_sIsA);
510 if (m_aRich != null)
511 m_aRich.fillMicroElement (ret);
512 if (m_aForeignElements != null)
513 for (final IMicroElement aForeignElement : m_aForeignElements)
514 ret.appendChild (aForeignElement.getClone ());
515 for (final PSInclude aInclude : m_aIncludes)
516 ret.appendChild (aInclude.getAsMicroElement ());
517 if (m_aTitle != null)
518 ret.appendChild (m_aTitle.getAsMicroElement ());
519 for (final IPSElement aContent : m_aContent)
520 ret.appendChild (aContent.getAsMicroElement ());
521 if (m_aForeignAttrs != null)
522 for (final Map.Entry <String, String> aEntry : m_aForeignAttrs.entrySet ())
523 ret.setAttribute (aEntry.getKey (), aEntry.getValue ());
524 return ret;
525 }
526
527 @Override
528 public String toString ()
529 {
530 return new ToStringGenerator (this).append ("abstract", m_bAbstract)
531 .appendIfNotNull ("id", m_sID)
532 .appendIfNotNull ("is-a", m_sIsA)
533 .appendIfNotNull ("rich", m_aRich)
534 .appendIf ("includes", m_aIncludes, CollectionHelper::isNotEmpty)
535 .appendIfNotNull ("title", m_aTitle)
536 .appendIf ("content", m_aContent, CollectionHelper::isNotEmpty)
537 .appendIf ("foreignAttrs", m_aForeignAttrs, CollectionHelper::isNotEmpty)
538 .appendIf ("foreignElements", m_aForeignElements, CollectionHelper::isNotEmpty)
539 .getToString ();
540 }
541 }