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