1 package eu.simuline.relana.model;
2
3 import eu.simuline.relana.expressions.FormulaDecl;
4
5 import java.util.List;
6
7 import java.util.Set;
8 import java.util.HashSet;
9 import java.util.TreeSet;
10 import java.util.Map;
11 import java.util.HashMap;
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public class CClass implements CClassLink {
33
34
35
36
37
38
39
40
41
42 public enum SClassModifier {
43
44
45
46
47
48 INPUT(),
49 OUTPUT();
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 static final Map<String, SClassModifier> NAME2MOD;
66
67 static {
68 NAME2MOD = new HashMap<String, SClassModifier>();
69 NAME2MOD.put("input", INPUT);
70 NAME2MOD.put("output", OUTPUT);
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public static SClassModifier get(String name) {
86 SClassModifier res = NAME2MOD.get(name);
87 if (res == null) {
88 throw new IllegalArgumentException
89 ("Unknown access modifier: \"" + name + "\". ");
90 }
91 return res;
92 }
93 }
94
95
96
97
98
99
100
101
102 public static final class SClassDecl {
103
104
105
106
107
108
109
110
111
112 private final boolean isRedeclare;
113
114
115
116
117 private final Set<SClassModifier> modifiers;
118
119
120
121
122 private final SClass sClass;
123
124
125
126
127
128 private final String name;
129
130
131
132
133 private final ProbDistr distr;
134
135
136
137
138 private FormulaDecl form;
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 public SClassDecl(boolean isRedeclare,
164 Set<SClassModifier> modifiers,
165 SClass sClass,
166 String name,
167 ProbDistr distr) {
168 this.isRedeclare = isRedeclare;
169 this.modifiers = modifiers;
170 this.sClass = sClass;
171 this.name = name;
172
173 this.distr = distr;
174 if (isInput() && (this.distr != null)) {
175 throw new IllegalArgumentException
176 ("SClass " + name + " is declared as input " +
177 "and at the same time a probability distribution " +
178 "is attached. ");
179 }
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 public void setFormula(FormulaDecl form) {
205 this.form = form;
206 if (isInput() && (this.form != null)) {
207 throw new IllegalArgumentException
208 ("SClass " + name + " is declared as input " +
209 "and at the same time a formula is attached. ");
210 }
211
212 if ((this.distr != null) && (this.form != null)) {
213 throw new IllegalArgumentException
214 ("Either a probability distribution may be given " +
215 "or a formula but not both. ");
216 }
217
218
219
220 if ((this.form != null) &&
221 !this.form.retType().equals(this.sClass.getType())) {
222 throw new IllegalArgumentException
223 ("Tried to assign formula \"" + this.form +
224 "\" with return type " + this.form.retType() +
225 " to variable \"" + this.name +
226 "\" with type " + this.sClass.getType() +
227 " which is not assignment compatible. ");
228 }
229 }
230
231 public SClass getSClass() {
232 return this.sClass;
233 }
234
235 public String getName() {
236 return this.name;
237 }
238
239
240
241
242
243
244
245 public boolean isInput() {
246 return this.modifiers.contains(SClassModifier.INPUT);
247 }
248
249
250
251
252
253
254
255 public boolean isOutput() {
256 return this.modifiers.contains(SClassModifier.OUTPUT);
257 }
258
259
260
261
262
263
264
265 public boolean isRedeclare() {
266 return this.isRedeclare;
267 }
268
269
270
271
272
273
274
275
276 ProbDistr getProbDistr() {
277 return this.distr;
278 }
279
280
281
282
283
284
285
286 FormulaDecl getFormulaDecl() {
287 return this.form;
288 }
289
290
291
292
293
294
295
296
297
298 SInstance getSInstance() {
299 return new SInstance(getSClass().getType(),
300 getProbDistr(),
301 getName());
302 }
303
304 public String toString() {
305 StringBuffer res = new StringBuffer();
306 res.append('\n');
307 if (this.isRedeclare) {
308 res.append("redeclare");
309 }
310
311 res.append(this.modifiers);
312 res.append(getSClass().getName());
313 res.append(getName());
314 if (this.distr != null) {
315 res.append(" distr: ");
316 res.append(this.distr.toString());
317 }
318
319 if (this.form != null) {
320 res.append(" formula: ");
321 res.append(this.form.toString());
322 }
323 return res.toString();
324 }
325
326
327 public boolean equals(Object obj) {
328 return super.equals(obj);
329 }
330
331
332 public int hashCode() {
333 return super.hashCode();
334 }
335
336 }
337
338
339
340
341
342
343
344
345
346
347
348 public static final CClass COMPONENT =
349 new CClass("Component",
350 Package.BUILD_IN,
351 null,
352 new HashMap<String, MapDecl>(),
353 new HashMap<String, CClassLink>(),
354 new HashMap<String, CClass.SClassDecl>()) {
355
356
357
358
359 @Override
360 public MapDecl getMapDecl(String name) {
361 return null;
362 }
363
364 @Override
365 public CClassLink getComponentCls(String name) {
366 return null;
367 }
368
369 @Override
370 public SClassDecl getEffectDecl(String name) {
371 return null;
372 }
373 @SuppressWarnings("PMD.SingletonClassReturningNewInstance")
374 @Override
375 public CInstance getInstance() {
376 return new CInstance();
377 }
378 @Override
379 Set<String> getComponentNames() {
380 return new TreeSet<String>();
381 }
382 @Override
383 Set<String> getEffectNames() {
384 return new TreeSet<String>();
385 }
386 @Override
387 void verify() throws VerifyException {
388
389 }
390 };
391
392
393
394
395
396
397
398
399 private final String cName;
400
401
402
403
404 private final Package pkg;
405
406
407
408
409
410
411
412 private final CClass superClass;
413
414
415
416
417 private final Map<String, MapDecl> maps;
418
419
420
421
422 private final Map<String, CClassLink> subComponents;
423
424
425
426
427 private final Map<String, SClassDecl> effects;
428
429
430
431
432
433
434
435
436
437
438 public static CClass getCClass(String cName,
439 Package pkg,
440 CClass superClass,
441 Map<String, MapDecl> maps,
442 Map<String, CClassLink> subComponents,
443 Map<String, SClassDecl> effects
444
445 ) {
446 return new CClass(cName, pkg, superClass,
447 maps,
448 subComponents,
449 effects);
450 }
451
452 public CClass(String cName,
453 Package pkg,
454 CClass superClass,
455 Map<String, MapDecl> maps,
456 Map<String, CClassLink> subComponents,
457 Map<String, SClassDecl> effects
458
459 ) {
460 this.cName = cName;
461 this.pkg = pkg;
462 this.superClass = superClass;
463 this.maps = maps;
464 this.subComponents = subComponents;
465 this.effects = effects;
466
467
468 }
469
470
471
472
473
474
475
476
477
478
479
480 public final String getName() {
481 return this.cName;
482 }
483
484
485
486
487
488
489
490 public final Package getPackage() {
491 return this.pkg;
492 }
493
494
495
496
497
498
499
500
501
502 public final CClass getSuperClass() {
503 return this.superClass;
504 }
505
506
507
508
509
510
511
512
513
514
515
516 @SuppressWarnings("checkstyle:designforextension")
517
518 public MapDecl getMapDecl(String name) {
519
520 MapDecl result = this.maps.get(name);
521 if (result != null) {
522 return result;
523 }
524 return getSuperClass().getMapDecl(name);
525
526 }
527
528
529
530
531
532
533
534 private Map<String, CClassLink> getName2ComponentClss() {
535 return this.subComponents;
536 }
537
538 @SuppressWarnings("checkstyle:designforextension")
539
540 public CClassLink getComponentCls(String name) {
541
542 CClassLink result = this.subComponents.get(name);
543 if (result != null) {
544 return result;
545 }
546 return getSuperClass().getComponentCls(name);
547 }
548
549 public final CClassLink getComponentCls(List<String> path) {
550 CClass curr = this;
551 for (String key : path) {
552 curr = (CClass) curr.getComponentCls(key);
553 }
554
555 return curr;
556 }
557
558 @SuppressWarnings("checkstyle:designforextension")
559
560 Set<String> getComponentNames() {
561
562 Set<String> result = new TreeSet<String>
563 (getSuperClass().getComponentNames());
564 result.addAll(getName2ComponentClss().keySet());
565 return result;
566 }
567
568
569
570
571 @SuppressWarnings("checkstyle:designforextension")
572
573 public SClassDecl getEffectDecl(String name) {
574
575 SClassDecl result = this.effects.get(name);
576 if (result != null) {
577 return result;
578 }
579
580 return getSuperClass().getEffectDecl(name);
581 }
582
583
584 public final SClassDecl getEffectDecl(List<String> path) {
585 CClass curr = this;
586 int ind = 0;
587 for (; ind < path.size() - 1; ind++) {
588 curr = (CClass) curr.getComponentCls(path.get(ind));
589
590 }
591
592 return curr.getEffectDecl(path.get(ind));
593 }
594
595 private Map<String, SClassDecl> getName2Effects() {
596 return this.effects;
597 }
598
599
600 @SuppressWarnings("checkstyle:designforextension")
601
602 Set<String> getEffectNames() {
603
604 Set<String> result =
605 new TreeSet<String>(getSuperClass().getEffectNames());
606 result.addAll(getName2Effects().keySet());
607 return result;
608 }
609
610
611
612
613
614 public final Set<SClassDecl> getEffectsRec() {
615 Set<SClassDecl> res = new HashSet<SClassDecl>();
616
617 for (SClassDecl decl : this.effects.values()) {
618 res.add(decl);
619 }
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638 return res;
639 }
640
641
642 public final CClassLink setComponent(String name, CClass cClass) {
643
644 return this.subComponents.put(name, cClass);
645 }
646
647 @SuppressWarnings("checkstyle:designforextension")
648
649 void verify() throws VerifyException {
650
651 getSuperClass().verify();
652
653
654
655 SClassDecl overwritten, overwrite;
656 for (Map.Entry<String, SClassDecl> entry
657 : getName2Effects().entrySet()) {
658 overwrite = entry.getValue();
659 overwritten = getSuperClass().getEffectDecl(entry.getKey());
660 if (overwrite.isRedeclare()) {
661
662
663
664 if (overwritten == null) {
665
666 throw new VerifyException
667 ("Found effect \"" + entry.getKey() +
668 "\" redeclared in class \"" + getName() +
669 "\" without being declared in any superclass. ");
670 }
671
672
673 if ((overwritten.isOutput() && !overwrite.isOutput()) ||
674 (overwritten.isInput () && !overwrite.isInput ())) {
675 throw new VerifyException
676 ("Weakened access priviligies of effect \"" +
677 entry.getKey() +
678 "\" by redeclaration in class " + getName() + ". ");
679 }
680
681
682
683
684
685
686 SClass currentSCls = overwrite.getSClass();
687
688
689 DeficiencyMap compMap = DeficiencyMap.identity(currentSCls);
690 assert compMap.getTarget() == overwrite.getSClass();
691 while (currentSCls != overwritten.getSClass()) {
692 assert compMap.getSource() == currentSCls;
693 if (currentSCls.getSuperClass() == null) {
694 throw new VerifyException
695 ("Redeclared effect \"" + entry.getKey() +
696 "\" of class " +
697 overwritten.getSClass().getName() +
698 " as " + overwrite.getSClass().getName() +
699 " which is no subclass. ");
700 }
701 compMap = compMap.compose(currentSCls.getDeficiencyMap());
702 currentSCls = currentSCls.getSuperClass();
703 }
704
705
706
707
708
709 } else {
710
711
712
713 if (overwritten != null) {
714
715 throw new VerifyException
716 ("Found effect \"" + entry.getKey() +
717 "\" declared in class \"" + getName() +
718 "\" and in a superclass: " + entry.getKey() +
719 "; consider redeclare. ");
720 }
721 }
722 }
723
724
725
726 Set<String> names =
727 new TreeSet<String>(getSuperClass().getComponentNames());
728 names.retainAll(getName2ComponentClss().keySet());
729 if (!names.isEmpty()) {
730 throw new VerifyException
731 ("Found components declared in class \"" + getName() +
732 "\" and in a superclass: " + names + ". ");
733 }
734 }
735
736
737
738
739
740
741
742
743 @SuppressWarnings({
744 "PMD.SingletonClassReturningNewInstance",
745 "PMD.SingleMethodSingleton",
746 "checkstyle:designforextension"})
747
748 public CInstance getInstance() {
749
750 CInstance cInstance = getSuperClass().getInstance();
751
752
753 CClass cClass;
754 for (Map.Entry<String, CClassLink> cEntry
755 : this.subComponents.entrySet()) {
756 cClass = (CClass) cEntry.getValue();
757
758 cInstance.addComponent(cEntry.getKey(),
759 cClass.getInstance());
760
761 }
762
763
764 SInstance sInstance;
765 SClassDecl decl;
766 Map<SClassDecl, SInstance> declWithFormulae =
767 new HashMap<SClassDecl, SInstance>();
768 for (Map.Entry<String, SClassDecl> sEntry
769 : this.effects.entrySet()) {
770 decl = sEntry.getValue();
771 sInstance = decl.getSInstance();
772
773
774 cInstance.addEffect(sEntry.getKey(), sInstance);
775 if (decl.getFormulaDecl() != null) {
776 declWithFormulae.put(decl, sInstance);
777 }
778 }
779
780
781 for (Map.Entry<SClassDecl, SInstance> entry
782 : declWithFormulae.entrySet()) {
783 entry.getValue().setFormula(entry.getKey()
784 .getFormulaDecl().resolve(cInstance));
785
786 }
787
788 return cInstance;
789 }
790
791 public void addOccurrence(CClassLoader.Occurrence occ) {
792
793 }
794
795 public final boolean isResolved() {
796 return true;
797 }
798
799 public final String toString() {
800 StringBuffer res = new StringBuffer();
801
802 res.append("\n<CClass name=\"");
803 res.append(this.cName);
804 res.append("\" package=\"");
805 res.append(this.pkg);
806 res.append("\" superClass=\"");
807 res.append(this.superClass.getName());
808 res.append("\">\n");
809 for (Map.Entry<String, MapDecl> entry
810 : this.maps.entrySet()) {
811 res.append("<map name=\"");
812 res.append(entry.getKey());
813 res.append("\"/>\n");
814 res.append(entry.getValue());
815 res.append("</map>");
816 }
817 for (Map.Entry<String, CClassLink> entry
818 : this.subComponents.entrySet()) {
819 res.append("<component name=\"");
820 res.append(entry.getKey());
821 res.append("\" class=\"");
822 res.append(entry.getValue().getName());
823 res.append("\"/>\n");
824 }
825
826 res.append("\n<effects>");
827 for (SClassDecl decl : this.effects.values()) {
828 res.append(decl.toString());
829 }
830 res.append("\n</effects>\n</CClass>\n");
831 return res.toString();
832 }
833
834 }