1 package org.andromda.core.metafacade;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.LinkedHashMap;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import org.andromda.core.common.AndroMDALogger;
11 import org.andromda.core.common.ExceptionUtils;
12 import org.andromda.core.profile.Profile;
13 import org.apache.commons.collections.keyvalue.MultiKey;
14 import org.apache.commons.lang.StringUtils;
15 import org.apache.log4j.Logger;
16
17
18
19
20
21
22
23
24
25
26
27 public final class MetafacadeFactory
28 implements Serializable
29 {
30 private static final long serialVersionUID = 34L;
31
32
33
34
35 private final Map<String, Map<String, Map<String, Object>>> metafacadeNamespaces = new LinkedHashMap<String, Map<String, Map<String, Object>>>();
36
37
38
39
40 private static MetafacadeFactory instance = null;
41
42 private MetafacadeFactory()
43 {
44
45 }
46
47
48
49
50
51
52 public static MetafacadeFactory getInstance()
53 {
54 if (instance == null)
55 {
56 instance = new MetafacadeFactory();
57 }
58 return instance;
59 }
60
61
62
63
64 private final MetafacadeCache cache = MetafacadeCache.newInstance();
65
66
67
68
69 private final MetafacadeMappings mappings = MetafacadeMappings.newInstance();
70
71
72
73
74
75 public void initialize()
76 {
77 this.mappings.initialize();
78 }
79
80
81
82
83 private final Profile profile = Profile.instance();
84
85
86
87
88 private String namespace;
89
90
91
92
93
94
95
96 public void setNamespace(final String namespace)
97 {
98 this.namespace = namespace;
99 this.profile.setNamespace(namespace);
100 this.cache.setNamespace(this.namespace);
101 }
102
103
104
105
106
107
108 public String getNamespace()
109 {
110 if (this.namespace == null)
111 {
112 throw new MetafacadeFactoryException("This metafacade factory's namespace must be populated before " +
113 "metafacade construction can occur");
114 }
115 return this.namespace;
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129 public MetafacadeBase createMetafacade(
130 final Object mappingObject,
131 final String context)
132 {
133 return this.createMetafacade(
134 mappingObject,
135 context,
136 null);
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 private MetafacadeBase createMetafacade(
155 final Object mappingObject,
156 final String context,
157 Class metafacadeClass)
158 {
159 final String methodName = "MetafacadeFactory.createMetafacade";
160 ExceptionUtils.checkNull(
161 "mappingObject",
162 mappingObject);
163
164
165 this.registerNamespaceProperties();
166
167
168 if (mappingObject instanceof MetafacadeBase)
169 {
170 return (MetafacadeBase)mappingObject;
171 }
172 try
173 {
174 final Collection<String> stereotypes = this.getModel().getStereotypeNames(mappingObject);
175 if (this.getLogger().isDebugEnabled())
176 {
177 this.getLogger().debug("mappingObject stereotypes --> '" + stereotypes + '\'');
178 }
179
180 MetafacadeMapping mapping = null;
181 if (metafacadeClass == null)
182 {
183 final MetafacadeMappings modelMetafacadeMappings = this.getModelMetafacadeMappings();
184 mapping = modelMetafacadeMappings.getMetafacadeMapping(
185 mappingObject,
186 this.getNamespace(),
187 context,
188 stereotypes);
189 if (this.getLogger().isDebugEnabled())
190 {
191 this.getLogger().debug("mappingObject getModelMetafacadeMappings for " + mappingObject + " namespace " + this.getNamespace() + " context " + context);
192 }
193 if (mapping != null)
194 {
195 metafacadeClass = mapping.getMetafacadeClass();
196 }
197 else
198 {
199
200 metafacadeClass = modelMetafacadeMappings.getDefaultMetafacadeClass(this.getNamespace());
201 if (this.getLogger().isDebugEnabled())
202 {
203 this.getLogger().warn(
204 "Meta object model class '" + mappingObject.getClass() +
205 "' has no corresponding meta facade class, default is being used --> '" + metafacadeClass +
206 '\'');
207 }
208 }
209 }
210
211 if (metafacadeClass == null)
212 {
213 throw new MetafacadeMappingsException(methodName + " metafacadeClass was not retrieved from mappings" +
214 " or specified as an argument in this method for mappingObject --> '" + mappingObject + '\'');
215 }
216 final MetafacadeBase metafacade = this.getMetafacade(
217 metafacadeClass,
218 mappingObject,
219 context,
220 mapping);
221
222
223
224 if (metafacade != null && !metafacade.isInitialized())
225 {
226 metafacade.setInitialized();
227 metafacade.initialize();
228 }
229 return metafacade;
230 }
231 catch (final Throwable throwable)
232 {
233 final String message =
234 "Failed to construct a meta facade of type '" + metafacadeClass + "' with mappingObject of type --> '" +
235 mappingObject.getClass() + '\'';
236 this.getLogger().error(message);
237 throw new MetafacadeFactoryException(message, throwable);
238 }
239 }
240
241
242
243
244
245
246
247 private MetafacadeMappings getModelMetafacadeMappings()
248 {
249 return this.mappings.getModelMetafacadeMappings(this.metafacadeModelNamespace);
250 }
251
252
253
254
255
256
257
258
259 public void validateAllMetafacades()
260 {
261 for (final MetafacadeBase metafacadeBase : this.getAllMetafacades())
262 {
263 metafacadeBase.validate(this.validationMessages);
264 }
265 }
266
267
268
269
270
271
272
273
274
275
276 protected MetafacadeBase createMetafacade(
277 final Object mappingObject,
278 final MetafacadeMapping mapping)
279 {
280 try
281 {
282 return this.getMetafacade(
283 mapping.getMetafacadeClass(),
284 mappingObject,
285 mapping.getContext(),
286 mapping);
287 }
288 catch (final Throwable throwable)
289 {
290 final String message =
291 "Failed to construct a meta facade of type '" + mapping.getMetafacadeClass() +
292 "' with mappingObject of type --> '" + mapping.getMappingClassNames() + '\'';
293 this.getLogger().error(message);
294 throw new MetafacadeFactoryException(message, throwable);
295 }
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 private MetafacadeBase getMetafacade(
312 final Class metafacadeClass,
313 final Object mappingObject,
314 final String context,
315 final MetafacadeMapping mapping)
316 throws Exception
317 {
318 MetafacadeBase metafacade = this.cache.get(
319 mappingObject,
320 metafacadeClass);
321 if (metafacade == null)
322 {
323 final MultiKey key = new MultiKey(mappingObject, metafacadeClass);
324 if (!this.metafacadesInCreation.contains(key))
325 {
326 this.metafacadesInCreation.add(
327 key);
328 if (mapping != null && mapping.isContextRoot())
329 {
330 metafacade = MetafacadeUtils.constructMetafacade(
331 metafacadeClass,
332 mappingObject,
333 null);
334
335 metafacade.setContextRoot(mapping.isContextRoot());
336 }
337 else
338 {
339 metafacade = MetafacadeUtils.constructMetafacade(
340 metafacadeClass,
341 mappingObject,
342 context);
343 }
344 this.metafacadesInCreation.remove(key);
345
346 this.cache.add(
347 mappingObject,
348 metafacade);
349 }
350 }
351
352 if (metafacade != null)
353 {
354
355 if (mapping != null && !mapping.getMetafacadeClass().equals(metafacadeClass))
356 {
357 metafacade.setContextRoot(false);
358 metafacade.resetMetafacadeContext(context);
359 }
360
361
362 final String metafacadeNamespace = metafacade.getMetafacadeNamespace();
363 if (metafacadeNamespace == null || !metafacadeNamespace.equals(this.getNamespace()))
364 {
365
366 metafacade.setNamespace(this.getNamespace());
367 metafacade.setLogger(this.getLogger());
368 }
369 }
370 return metafacade;
371 }
372
373
374
375
376
377 private final Collection<MultiKey> metafacadesInCreation = new ArrayList<MultiKey>();
378
379
380
381
382
383
384
385 public MetafacadeBase createMetafacade(final Object mappingObject)
386 {
387 return this.createMetafacade(
388 mappingObject,
389 null,
390 null);
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404
405 public MetafacadeBase createFacadeImpl(
406 final String interfaceName,
407 final Object mappingObject,
408 final String context)
409 {
410 ExceptionUtils.checkEmpty(
411 "interfaceName",
412 interfaceName);
413 ExceptionUtils.checkNull(
414 "mappingObject",
415 mappingObject);
416
417 Class metafacadeClass = null;
418 try
419 {
420 metafacadeClass = this.metafacadeImpls.getMetafacadeImplClass(interfaceName);
421 return this.createMetafacade(
422 mappingObject,
423 context,
424 metafacadeClass);
425 }
426 catch (final Throwable throwable)
427 {
428 final String message =
429 "Failed to construct a meta facade of type '" + metafacadeClass + "' with mappingObject of type --> '" +
430 mappingObject.getClass().getName() + '\'';
431 this.getLogger().error(message);
432 throw new MetafacadeFactoryException(message, throwable);
433 }
434 }
435
436
437
438
439
440
441
442
443
444
445
446
447 protected Collection<MetafacadeBase> createMetafacades(
448 final Collection mappingObjects,
449 final String contextName)
450 {
451 final Collection<MetafacadeBase> metafacades = new ArrayList<MetafacadeBase>();
452 if (mappingObjects != null && !mappingObjects.isEmpty())
453 {
454 for (final Object mappingObject : mappingObjects)
455 {
456 if (this.getLogger().isDebugEnabled())
457 {
458 this.getLogger().debug("MetafacadeFactory createMetafacade for namespace " + this.getNamespace() + " model " + this.getModel() + " contextName " + contextName + " mappingObject " + mappingObject);
459 }
460 metafacades.add(this.createMetafacade(
461 mappingObject,
462 contextName,
463 null));
464 }
465 }
466 return metafacades;
467 }
468
469
470
471
472
473
474
475
476
477
478 public Collection<MetafacadeBase> createMetafacades(final Collection mappingObjects)
479 {
480 return this.createMetafacades(
481 mappingObjects,
482 null);
483 }
484
485
486
487
488 private ModelAccessFacade model;
489
490
491
492
493
494
495
496 public ModelAccessFacade getModel()
497 {
498 if (this.model == null)
499 {
500 throw new MetafacadeFactoryException("This metafacade factory's model must be populated before " +
501 "metafacade construction can occur");
502 }
503 return this.model;
504 }
505
506
507
508
509 private MetafacadeImpls metafacadeImpls = MetafacadeImpls.instance();
510
511
512
513
514 private String metafacadeModelNamespace;
515
516
517
518
519
520
521
522 public void setModel(
523 final ModelAccessFacade model,
524 final String metafacadeModelNamespace)
525 {
526 this.metafacadeModelNamespace = metafacadeModelNamespace;
527
528
529
530 this.metafacadeImpls.setMetafacadeModelNamespace(metafacadeModelNamespace);
531 this.model = model;
532 }
533
534
535
536
537
538
539 final Logger getLogger()
540 {
541 return AndroMDALogger.getNamespaceLogger(this.getNamespace());
542 }
543
544
545
546
547
548
549
550
551
552
553 final void registerProperty(
554 final String namespace,
555 final String metafacadeName,
556 final String name,
557 final Object value)
558 {
559 ExceptionUtils.checkEmpty(
560 "name",
561 name);
562 Map<String, Map<String, Object>> metafacadeNamespace = this.metafacadeNamespaces.get(namespace);
563 if (metafacadeNamespace == null)
564 {
565 metafacadeNamespace = new LinkedHashMap<String, Map<String, Object>>();
566 this.metafacadeNamespaces.put(
567 namespace,
568 metafacadeNamespace);
569 }
570 Map<String, Object> propertyNamespace = metafacadeNamespace.get(metafacadeName);
571 if (propertyNamespace == null)
572 {
573 propertyNamespace = new LinkedHashMap<String, Object>();
574 metafacadeNamespace.put(
575 metafacadeName,
576 propertyNamespace);
577 }
578 propertyNamespace.put(
579 name,
580 value);
581 }
582
583
584
585
586
587
588
589
590
591 final void registerProperty(
592 final String metafacadeName,
593 final String name,
594 final Object value)
595 {
596 this.registerProperty(
597 this.getNamespace(),
598 metafacadeName,
599 name,
600 value);
601 }
602
603
604
605
606
607
608
609 private Map<String, Object> getMetafacadePropertyNamespace(final MetafacadeBase metafacade)
610 {
611 Map<String, Object> metafacadeNamespace = null;
612 if (metafacade != null)
613 {
614 Map<String, Map<String, Object>> namespace = this.metafacadeNamespaces.get(this.getNamespace());
615 if (namespace != null)
616 {
617 metafacadeNamespace = namespace.get(metafacade.getMetafacadeName());
618 }
619 }
620 return metafacadeNamespace;
621 }
622
623
624
625
626
627
628
629
630
631 final boolean isPropertyRegistered(
632 final MetafacadeBase metafacade,
633 final String name)
634 {
635 final Map<String, Object> propertyNamespace = this.getMetafacadePropertyNamespace(metafacade);
636 return propertyNamespace != null && propertyNamespace.containsKey(name);
637 }
638
639
640
641
642
643
644
645
646
647 private Object findProperty(
648 final MetafacadeBase metafacade,
649 final String name)
650 {
651 final Map<String, Object> propertyNamespace = this.getMetafacadePropertyNamespace(metafacade);
652 return propertyNamespace != null ? propertyNamespace.get(name) : null;
653 }
654
655
656
657
658
659
660
661
662
663 final Object getRegisteredProperty(
664 final MetafacadeBase metafacade,
665 final String name)
666 {
667 final String methodName = "MetafacadeFactory.getRegisteredProperty";
668 final Object registeredProperty = this.findProperty(
669 metafacade,
670 name);
671 if (registeredProperty == null && !this.isPropertyRegistered(
672 metafacade,
673 name))
674 {
675 throw new MetafacadeFactoryException(methodName + " - no property '" + name +
676 "' registered under metafacade '" + metafacade.getMetafacadeName() + "' for namespace '" + this.getNamespace() +
677 '\'');
678 }
679 return registeredProperty;
680 }
681
682
683
684
685
686 private final Collection<ModelValidationMessage> validationMessages = new LinkedHashSet<ModelValidationMessage>();
687
688
689
690
691
692
693
694 public List<ModelValidationMessage> getValidationMessages()
695 {
696 return new ArrayList<ModelValidationMessage>(this.validationMessages);
697 }
698
699
700
701
702
703 private final Map<String, Collection<MetafacadeBase>> allMetafacades = new LinkedHashMap<String, Collection<MetafacadeBase>>();
704
705
706
707
708
709
710
711
712
713
714
715
716
717 public Collection<MetafacadeBase> getAllMetafacades()
718 {
719 final String namespace = this.getNamespace();
720 Collection<MetafacadeBase> metafacades = null;
721 if (this.getModel() != null)
722 {
723 metafacades = allMetafacades.get(namespace);
724 if (metafacades == null)
725 {
726 metafacades = this.createMetafacades(this.getModel().getModelElements());
727 allMetafacades.put(
728 namespace,
729 metafacades);
730 }
731 if (metafacades != null)
732 {
733 metafacades = new ArrayList<MetafacadeBase>(metafacades);
734 }
735 }
736 return metafacades;
737 }
738
739
740
741
742 private final Map<String, Map<String, Collection<MetafacadeBase>>> metafacadesByStereotype
743 = new LinkedHashMap<String, Map<String, Collection<MetafacadeBase>>>();
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758 public Collection<MetafacadeBase> getMetafacadesByStereotype(final String stereotype)
759 {
760 final String namespace = this.getNamespace();
761 Collection<MetafacadeBase> metafacades = null;
762 if (this.getModel() != null)
763 {
764 Map<String, Collection<MetafacadeBase>> stereotypeMetafacades = this.metafacadesByStereotype.get(namespace);
765 if (stereotypeMetafacades == null)
766 {
767 stereotypeMetafacades = new LinkedHashMap<String, Collection<MetafacadeBase>>();
768 }
769 metafacades = stereotypeMetafacades.get(stereotype);
770 if (metafacades == null)
771 {
772 metafacades = this.createMetafacades(this.getModel().findByStereotype(stereotype));
773 stereotypeMetafacades.put(
774 stereotype,
775 metafacades);
776 this.metafacadesByStereotype.put(
777 namespace,
778 stereotypeMetafacades);
779 }
780 if (metafacades != null)
781 {
782 metafacades = new ArrayList<MetafacadeBase>(metafacades);
783 }
784 }
785 return metafacades;
786 }
787
788
789
790
791
792 public void shutdown()
793 {
794 this.clearCaches();
795 this.metafacadeNamespaces.clear();
796 this.mappings.shutdown();
797 this.model = null;
798 MetafacadeFactory.instance = null;
799
800
801 this.profile.shutdown();
802 }
803
804
805
806
807 private void registerNamespaceProperties()
808 {
809
810 if (this.metafacadeNamespaces.isEmpty())
811 {
812 if (StringUtils.isNotBlank(this.metafacadeModelNamespace))
813 {
814 final MetafacadeMappings modelMappings = this.getModelMetafacadeMappings();
815 if (modelMappings != null)
816 {
817 modelMappings.registerAllProperties();
818 }
819 }
820 }
821 }
822
823
824
825
826
827 public void reset()
828 {
829
830 this.profile.refresh();
831
832
833 this.metafacadeNamespaces.clear();
834
835
836 this.registerNamespaceProperties();
837
838
839 this.clearCaches();
840 }
841
842
843
844
845
846
847 public void clearCaches()
848 {
849 this.validationMessages.clear();
850 this.allMetafacades.clear();
851 this.metafacadesByStereotype.clear();
852 this.cache.clear();
853 this.metafacadesInCreation.clear();
854 }
855 }