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.ArrayList;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.annotation.Nonnegative;
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import javax.annotation.concurrent.NotThreadSafe;
28
29 import com.helger.commons.ValueEnforcer;
30 import com.helger.commons.annotations.ReturnsMutableCopy;
31 import com.helger.commons.collections.ContainerHelper;
32 import com.helger.commons.microdom.IMicroElement;
33 import com.helger.commons.microdom.impl.MicroElement;
34 import com.helger.commons.string.StringHelper;
35 import com.helger.commons.string.ToStringGenerator;
36 import com.helger.schematron.CSchematron;
37 import com.helger.schematron.CSchematronXML;
38 import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
39
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 @NotThreadSafe
147 public class PSPattern implements IPSElement, IPSHasID, IPSHasForeignElements, IPSHasIncludes, IPSHasLets, IPSHasRichGroup
148 {
149 private boolean m_bAbstract = false;
150 private String m_sID;
151 private String m_sIsA;
152 private PSRichGroup m_aRich;
153 private final List <PSInclude> m_aIncludes = new ArrayList <PSInclude> ();
154 private PSTitle m_aTitle;
155 private final List <IPSElement> m_aContent = new ArrayList <IPSElement> ();
156 private Map <String, String> m_aForeignAttrs;
157 private List <IMicroElement> m_aForeignElements;
158
159 public PSPattern ()
160 {}
161
162 public boolean isValid (@Nonnull final IPSErrorHandler aErrorHandler)
163 {
164
165 if (m_bAbstract && StringHelper.hasNoText (m_sID))
166 {
167 aErrorHandler.error (this, "abstract <pattern> does not have an 'id'");
168 return false;
169 }
170
171 if (m_bAbstract && StringHelper.hasText (m_sIsA))
172 {
173 aErrorHandler.error (this, "abstract <pattern> may not have an 'is-a'");
174 return false;
175 }
176 if (StringHelper.hasNoText (m_sIsA))
177 {
178
179 for (final IPSElement aContent : m_aContent)
180 if (aContent instanceof PSParam)
181 {
182 aErrorHandler.error (this, "<pattern> without 'is-a' may not contain <param>s");
183 return false;
184 }
185 }
186 else
187 {
188
189 for (final IPSElement aContent : m_aContent)
190 {
191 if (aContent instanceof PSRule)
192 {
193 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <rule>s");
194 return false;
195 }
196 if (aContent instanceof PSLet)
197 {
198 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <let>s");
199 return false;
200 }
201 }
202 }
203
204 for (final PSInclude aInclude : m_aIncludes)
205 if (!aInclude.isValid (aErrorHandler))
206 return false;
207 if (m_aTitle != null && !m_aTitle.isValid (aErrorHandler))
208 return false;
209 for (final IPSElement aContent : m_aContent)
210 if (!aContent.isValid (aErrorHandler))
211 return false;
212 return true;
213 }
214
215 public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
216 {
217
218 if (m_bAbstract && StringHelper.hasNoText (m_sID))
219 aErrorHandler.error (this, "abstract <pattern> does not have an 'id'");
220
221 if (m_bAbstract && StringHelper.hasText (m_sIsA))
222 aErrorHandler.error (this, "abstract <pattern> may not have an 'is-a'");
223 if (StringHelper.hasNoText (m_sIsA))
224 {
225
226 for (final IPSElement aContent : m_aContent)
227 if (aContent instanceof PSParam)
228 aErrorHandler.error (this, "<pattern> without 'is-a' may not contain <param>s");
229 }
230 else
231 {
232
233 for (final IPSElement aContent : m_aContent)
234 {
235 if (aContent instanceof PSRule)
236 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <rule>s");
237 if (aContent instanceof PSLet)
238 aErrorHandler.error (this, "<pattern> with 'is-a' may not contain <let>s");
239 }
240 }
241
242 for (final PSInclude aInclude : m_aIncludes)
243 aInclude.validateCompletely (aErrorHandler);
244 if (m_aTitle != null)
245 m_aTitle.validateCompletely (aErrorHandler);
246 for (final IPSElement aContent : m_aContent)
247 aContent.validateCompletely (aErrorHandler);
248 }
249
250 public boolean isMinimal ()
251 {
252 if (m_bAbstract)
253 return false;
254 if (StringHelper.hasText (m_sIsA))
255 return false;
256 for (final PSInclude aInclude : m_aIncludes)
257 if (!aInclude.isMinimal ())
258 return false;
259 if (m_aTitle != null && !m_aTitle.isMinimal ())
260 return false;
261 for (final IPSElement aContent : m_aContent)
262 if (!aContent.isMinimal ())
263 return false;
264 return true;
265 }
266
267 public void addForeignElement (@Nonnull final IMicroElement aForeignElement)
268 {
269 ValueEnforcer.notNull (aForeignElement, "ForeignElement");
270 if (aForeignElement.hasParent ())
271 throw new IllegalArgumentException ("ForeignElement already has a parent!");
272 if (m_aForeignElements == null)
273 m_aForeignElements = new ArrayList <IMicroElement> ();
274 m_aForeignElements.add (aForeignElement);
275 }
276
277 public void addForeignElements (@Nonnull final List <IMicroElement> aForeignElements)
278 {
279 ValueEnforcer.notNull (aForeignElements, "ForeignElements");
280 for (final IMicroElement aForeignElement : aForeignElements)
281 addForeignElement (aForeignElement);
282 }
283
284 public boolean hasForeignElements ()
285 {
286 return m_aForeignElements != null && !m_aForeignElements.isEmpty ();
287 }
288
289 @Nonnull
290 @ReturnsMutableCopy
291 public List <IMicroElement> getAllForeignElements ()
292 {
293 return ContainerHelper.newList (m_aForeignElements);
294 }
295
296 public void addForeignAttribute (@Nonnull final String sAttrName, @Nonnull final String sAttrValue)
297 {
298 ValueEnforcer.notNull (sAttrName, "AttrName");
299 ValueEnforcer.notNull (sAttrValue, "AttrValue");
300 if (m_aForeignAttrs == null)
301 m_aForeignAttrs = new LinkedHashMap <String, String> ();
302 m_aForeignAttrs.put (sAttrName, sAttrValue);
303 }
304
305 public void addForeignAttributes (@Nonnull final Map <String, String> aForeignAttrs)
306 {
307 ValueEnforcer.notNull (aForeignAttrs, "ForeignAttrs");
308 for (final Map.Entry <String, String> aEntry : aForeignAttrs.entrySet ())
309 addForeignAttribute (aEntry.getKey (), aEntry.getValue ());
310 }
311
312 public boolean hasForeignAttributes ()
313 {
314 return m_aForeignAttrs != null && !m_aForeignAttrs.isEmpty ();
315 }
316
317 @Nonnull
318 @ReturnsMutableCopy
319 public Map <String, String> getAllForeignAttributes ()
320 {
321 return ContainerHelper.newOrderedMap (m_aForeignAttrs);
322 }
323
324 public void setAbstract (final boolean bAbstract)
325 {
326 m_bAbstract = bAbstract;
327 }
328
329 public boolean isAbstract ()
330 {
331 return m_bAbstract;
332 }
333
334 public void setID (@Nullable final String sID)
335 {
336 m_sID = sID;
337 }
338
339 public boolean hasID ()
340 {
341 return m_sID != null;
342 }
343
344 @Nullable
345 public String getID ()
346 {
347 return m_sID;
348 }
349
350 public void setIsA (@Nullable final String sIsA)
351 {
352 m_sIsA = sIsA;
353 }
354
355 @Nullable
356 public String getIsA ()
357 {
358 return m_sIsA;
359 }
360
361 public void setRich (@Nullable final PSRichGroup aRich)
362 {
363 m_aRich = aRich;
364 }
365
366 public boolean hasRich ()
367 {
368 return m_aRich != null;
369 }
370
371 @Nullable
372 public PSRichGroup getRich ()
373 {
374 return m_aRich;
375 }
376
377 @Nullable
378 public PSRichGroup getRichClone ()
379 {
380 return m_aRich == null ? null : m_aRich.getClone ();
381 }
382
383 public void addInclude (@Nonnull final PSInclude aInclude)
384 {
385 ValueEnforcer.notNull (aInclude, "Include");
386 m_aIncludes.add (aInclude);
387 }
388
389 public boolean hasAnyInclude ()
390 {
391 return !m_aIncludes.isEmpty ();
392 }
393
394 @Nonnull
395 @ReturnsMutableCopy
396 public List <PSInclude> getAllIncludes ()
397 {
398 return ContainerHelper.newList (m_aIncludes);
399 }
400
401 public void setTitle (@Nullable final PSTitle aTitle)
402 {
403 m_aTitle = aTitle;
404 }
405
406 @Nullable
407 public PSTitle getTitle ()
408 {
409 return m_aTitle;
410 }
411
412 public boolean hasTitle ()
413 {
414 return m_aTitle != null;
415 }
416
417 public void addRule (@Nonnull final PSRule aRule)
418 {
419 ValueEnforcer.notNull (aRule, "Rule");
420 m_aContent.add (aRule);
421 }
422
423 @Nullable
424 public PSRule getRuleOfID (@Nullable final String sID)
425 {
426 if (StringHelper.hasText (sID))
427 for (final IPSElement aElement : m_aContent)
428 if (aElement instanceof PSRule)
429 {
430 final PSRule aRule = (PSRule) aElement;
431 if (sID.equals (aRule.getID ()))
432 return aRule;
433 }
434 return null;
435 }
436
437 @Nonnull
438 @ReturnsMutableCopy
439 public List <PSRule> getAllRules ()
440 {
441 final List <PSRule> ret = new ArrayList <PSRule> ();
442 for (final IPSElement aElement : m_aContent)
443 if (aElement instanceof PSRule)
444 ret.add ((PSRule) aElement);
445 return ret;
446 }
447
448 @Nonnegative
449 public int getRuleCount ()
450 {
451 int ret = 0;
452 for (final IPSElement aElement : m_aContent)
453 if (aElement instanceof PSRule)
454 ret++;
455 return ret;
456 }
457
458 public void addParam (@Nonnull final PSParam aParam)
459 {
460 ValueEnforcer.notNull (aParam, "Param");
461 m_aContent.add (aParam);
462 }
463
464 @Nonnull
465 @ReturnsMutableCopy
466 public List <PSParam> getAllParams ()
467 {
468 final List <PSParam> ret = new ArrayList <PSParam> ();
469 for (final IPSElement aElement : m_aContent)
470 if (aElement instanceof PSParam)
471 ret.add ((PSParam) aElement);
472 return ret;
473 }
474
475 public boolean hasAnyParam ()
476 {
477 for (final IPSElement aElement : m_aContent)
478 if (aElement instanceof PSParam)
479 return true;
480 return false;
481 }
482
483 public void addP (@Nonnull final PSP aP)
484 {
485 ValueEnforcer.notNull (aP, "P");
486 m_aContent.add (aP);
487 }
488
489 @Nonnull
490 @ReturnsMutableCopy
491 public List <PSP> getAllPs ()
492 {
493 final List <PSP> ret = new ArrayList <PSP> ();
494 for (final IPSElement aElement : m_aContent)
495 if (aElement instanceof PSP)
496 ret.add ((PSP) aElement);
497 return ret;
498 }
499
500 public void addLet (@Nonnull final PSLet aLet)
501 {
502 ValueEnforcer.notNull (aLet, "Let");
503 m_aContent.add (aLet);
504 }
505
506 public boolean hasAnyLet ()
507 {
508 for (final IPSElement aElement : m_aContent)
509 if (aElement instanceof PSLet)
510 return true;
511 return false;
512 }
513
514 @Nonnull
515 @ReturnsMutableCopy
516 public List <PSLet> getAllLets ()
517 {
518 final List <PSLet> ret = new ArrayList <PSLet> ();
519 for (final IPSElement aElement : m_aContent)
520 if (aElement instanceof PSLet)
521 ret.add ((PSLet) aElement);
522 return ret;
523 }
524
525 @Nonnull
526 @ReturnsMutableCopy
527 public Map <String, String> getAllLetsAsMap ()
528 {
529 final Map <String, String> ret = new LinkedHashMap <String, String> ();
530 for (final IPSElement aElement : m_aContent)
531 if (aElement instanceof PSLet)
532 {
533 final PSLet aLet = (PSLet) aElement;
534 ret.put (aLet.getName (), aLet.getValue ());
535 }
536 return ret;
537 }
538
539
540
541
542
543 @Nonnull
544 @ReturnsMutableCopy
545 public List <IPSElement> getAllContentElements ()
546 {
547 return ContainerHelper.newList (m_aContent);
548 }
549
550 @Nonnull
551 public IMicroElement getAsMicroElement ()
552 {
553 final IMicroElement ret = new MicroElement (CSchematron.NAMESPACE_SCHEMATRON, CSchematronXML.ELEMENT_PATTERN);
554 if (m_bAbstract)
555 ret.setAttribute (CSchematronXML.ATTR_ABSTRACT, "true");
556 ret.setAttribute (CSchematronXML.ATTR_ID, m_sID);
557 ret.setAttribute (CSchematronXML.ATTR_IS_A, m_sIsA);
558 if (m_aRich != null)
559 m_aRich.fillMicroElement (ret);
560 if (m_aForeignElements != null)
561 for (final IMicroElement aForeignElement : m_aForeignElements)
562 ret.appendChild (aForeignElement.getClone ());
563 for (final PSInclude aInclude : m_aIncludes)
564 ret.appendChild (aInclude.getAsMicroElement ());
565 if (m_aTitle != null)
566 ret.appendChild (m_aTitle.getAsMicroElement ());
567 for (final IPSElement aContent : m_aContent)
568 ret.appendChild (aContent.getAsMicroElement ());
569 if (m_aForeignAttrs != null)
570 for (final Map.Entry <String, String> aEntry : m_aForeignAttrs.entrySet ())
571 ret.setAttribute (aEntry.getKey (), aEntry.getValue ());
572 return ret;
573 }
574
575 @Override
576 public String toString ()
577 {
578 return new ToStringGenerator (this).append ("abstract", m_bAbstract)
579 .appendIfNotNull ("id", m_sID)
580 .appendIfNotNull ("is-a", m_sIsA)
581 .appendIfNotNull ("rich", m_aRich)
582 .appendIfNotEmpty ("includes", m_aIncludes)
583 .appendIfNotNull ("title", m_aTitle)
584 .appendIfNotEmpty ("content", m_aContent)
585 .appendIfNotEmpty ("foreignAttrs", m_aForeignAttrs)
586 .appendIfNotEmpty ("foreignElements", m_aForeignElements)
587 .toString ();
588 }
589 }