View Javadoc
1   /*
2    * #%L
3    * EUGene :: EUGene
4    * %%
5    * Copyright (C) 2004 - 2010 CodeLutin
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 3 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20   * #L%
21   */
22  
23  package org.nuiton.eugene.models.object.xml;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.codehaus.plexus.component.annotations.Component;
29  import org.nuiton.eugene.ModelHelper;
30  import org.nuiton.eugene.ModelReader;
31  import org.nuiton.eugene.models.Model;
32  import org.nuiton.eugene.models.object.ObjectModel;
33  import org.nuiton.eugene.models.object.ObjectModelAttribute;
34  import org.nuiton.eugene.models.object.ObjectModelClass;
35  import org.nuiton.eugene.models.object.ObjectModelClassifier;
36  import org.nuiton.eugene.models.object.ObjectModelEnumeration;
37  import org.nuiton.eugene.models.object.ObjectModelInterface;
38  import org.nuiton.eugene.models.object.ObjectModelPackage;
39  
40  import java.util.ArrayList;
41  import java.util.Collection;
42  import java.util.HashMap;
43  import java.util.Iterator;
44  import java.util.LinkedHashSet;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  
49  /**
50   * Implementation class for the root node abstraction of object model trees.
51   * This an entry point for browsing a model tree. This object offers as well
52   * several facilities for a direct access to some of the object model elements.
53   * In this concrete class, the tree is build by parsing an object model xml
54   * description using lutinxml XMLObjectParser.
55   *
56   * Created: 14 janv. 2004
57   *
58   * @author Cédric Pineau - pineau@codelutin.com
59   */
60  @Component(role = Model.class, hint = "objectmodel")
61  public class ObjectModelImpl implements ObjectModel {
62  
63      /** logger */
64      private static final Log log = LogFactory.getLog(ObjectModelImpl.class);
65  
66      protected String name;
67  
68      protected String version;
69  
70      protected Map<String, ObjectModelClass> classes = new HashMap<>();
71  
72      protected Map<String, ObjectModelPackage> packages = new HashMap<>();
73  
74      protected Map<String, ObjectModelInterface> interfaces = new HashMap<>();
75  
76      protected Map<String, ObjectModelClassifier> classifiers = new HashMap<>();
77  
78      protected Map<String, ObjectModelEnumeration> enumerations = new HashMap<>();
79  
80      protected List<String> comments = new ArrayList<>();
81  
82      protected Map<String, String> tagValues = new HashMap<>();
83  
84      /**
85       * Used to add others specific object to the model
86       * The key defined must be unique to get the significative extension associated to
87       */
88      private Map<String, Object> extensions = new HashMap<>();
89  
90      @Override
91      public String getModelType() {
92          return ModelHelper.ModelType.OBJECT.getAlias();
93      }
94  
95      public void setName(String name) {
96          this.name = name;
97      }
98  
99      public void setVersion(String version) {
100         this.version = version;
101     }
102 
103     @Override
104     public String getVersion() {
105         return version;
106     }
107 
108     public void addPackage(ObjectModelPackageImpl aPackage) {
109         aPackage.postInit();
110         aPackage.setObjectModelImpl(this);
111 
112         if (!aPackage.isExtern()) {
113             ObjectModelPackageImpl initialElement = (ObjectModelPackageImpl)
114                     packages.get(aPackage.getName());
115             if (initialElement == null) {
116                 packages.put(aPackage.getName(), aPackage);
117             } else {
118 
119                 // La package existe déjà. On va prendre tout ce que contient la
120                 // nouvelle package et l'ajouter à la précédente si nécessaire.
121 
122                 mergePackages(initialElement, aPackage);
123             }
124         }
125     }
126 
127     public void addClass(ObjectModelClassImpl clazz) {
128         //if (clazz == null)
129         //    return new ObjectModelClassImpl(this, null);
130         clazz.postInit();
131         clazz.setObjectModelImpl(this);
132 
133         if (!clazz.isExtern()) {
134             ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
135                     classes.get(clazz.getQualifiedName());
136             if (initialElement == null) {
137                 classes.put(clazz.getQualifiedName(), clazz);
138                 classifiers.put(clazz.getQualifiedName(), clazz);
139             } else {
140                 if (!(initialElement instanceof ObjectModelClassImpl)) {
141                     throw new IllegalArgumentException(
142                             "\"" + clazz + "\" is incompatible with already " +
143                                     "defined element \"" + initialElement + "\"");
144                 }
145                 ObjectModelClassImpl initialClazz =
146                         (ObjectModelClassImpl) initialElement;
147 
148                 // La classe existe déjà. On va prendre tout ce que contient la
149                 // nouvelle classe et l'ajouter à la précédente si nécessaire.
150 
151                 mergeClasses(initialClazz, clazz);
152 //                clazz = initialClazz;
153             }
154         }
155         //return clazz;
156     }
157 
158     public void addAssociationClass(ObjectModelAssociationClassImpl clazz) {
159         //if (clazz == null)
160         //    return new ObjectModelAssociationClassImpl(this, null);
161         clazz.postInit();
162         clazz.setObjectModelImpl(this);
163 
164         if (!clazz.isExtern()) {
165             ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
166                     classes.get(clazz.getQualifiedName());
167             if (initialElement == null) {
168                 classes.put(clazz.getQualifiedName(), clazz);
169                 classifiers.put(clazz.getQualifiedName(), clazz);
170             } else {
171                 if (!(initialElement instanceof ObjectModelAssociationClassImpl)) {
172                     throw new IllegalArgumentException(
173                             "\"" + clazz + "\" is incompatible with " +
174                                     "already defined element \"" + initialElement +
175                                     "\""
176                     );
177                 }
178                 ObjectModelAssociationClassImpl initialClazz =
179                         (ObjectModelAssociationClassImpl) initialElement;
180 
181                 mergeAssociationClasses(initialClazz, clazz);
182 //                clazz = initialClazz;
183             }
184         }
185         //return clazz;
186     }
187 
188     public void addComment(String comment) {
189         comments.add(comment);
190     }
191 
192     /**
193      * Returns the name of this model.
194      *
195      * @return the name of this model.
196      */
197     @Override
198     public String getName() {
199         return name;
200     }
201 
202 
203     @Override
204     public Collection<ObjectModelPackage> getPackages() {
205         return packages.values();
206     }
207 
208     @Override
209     public ObjectModelPackage getPackage(String packageName) {
210         return packages.get(packageName);
211     }
212 
213     @Override
214     public ObjectModelPackage getPackage(ObjectModelClassifier classifier) {
215         return getPackage(classifier.getPackageName());
216     }
217 
218     @Override
219     public boolean hasPackage(String packageName) {
220         return packages.containsKey(packageName);
221     }
222 
223     /**
224      * Returns all classifiers defined in this model.
225      *
226      * @return a Collection containing all ObjectModelClassifier for this model.
227      * @see ObjectModelClassifier
228      */
229     @Override
230     public Collection<ObjectModelClassifier> getClassifiers() {
231         return classifiers.values();
232     }
233 
234     /**
235      * Returns the classifier corresponding to the given qualified name, or null
236      * if the model contains no classifier for this qualified name.
237      *
238      * @param qualifiedClassifierName -
239      *                                the qualified name of the classifier to retrieve.
240      * @return the ObjectModelClassifier of the found classifier, or null if the
241      * model contains no classifier for this qualified name.
242      */
243     @Override
244     public ObjectModelClassifier getClassifier(String qualifiedClassifierName) {
245         return qualifiedClassifierName == null ? null
246                 : classifiers.get(qualifiedClassifierName);
247     }
248 
249     /**
250      * Returns all classes defined in this model.
251      *
252      * @return a Collection containing all ObjectModelClass for this model.
253      * @see ObjectModelClass
254      */
255     @Override
256     public Collection<ObjectModelClass> getClasses() {
257         return classes.values();
258     }
259 
260     /**
261      * Returns the class corresponding to the given qualified name, or null if
262      * the model contains no class for this qualified name.
263      *
264      * @param qualifiedClassName -
265      *                           the qualified name of the class to retrieve.
266      * @return the ObjectModelClass of the found class, or null if the model
267      * contains no class for this qualified name.
268      */
269     @Override
270     public ObjectModelClass getClass(String qualifiedClassName) {
271         if (qualifiedClassName == null) {
272             return null;
273         }
274         if (!hasClass(qualifiedClassName)) {
275             if (log.isDebugEnabled()) {
276                 log.debug("Class " + qualifiedClassName + " not found in model");
277             }
278             return null;
279         }
280         return classes.get(qualifiedClassName);
281     }
282 
283     @Override
284     public boolean hasClass(String qualifiedClassName) {
285         boolean hasClass = classes.containsKey(qualifiedClassName);
286         return hasClass;
287     }
288 
289     public void addInterface(ObjectModelInterfaceImpl interfacez) {
290         //if (interfacez == null)
291         //    return new ObjectModelInterfaceImpl(this, null);
292         interfacez.postInit();
293         interfacez.setObjectModelImpl(this);
294 
295         if (!interfacez.isExtern()) {
296             ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
297                     interfaces.get(interfacez.getQualifiedName());
298             if (initialElement == null) {
299                 interfaces.put(interfacez.getQualifiedName(), interfacez);
300                 classifiers.put(interfacez.getQualifiedName(), interfacez);
301             } else {
302                 if (!(initialElement instanceof ObjectModelInterfaceImpl)) {
303                     throw new IllegalArgumentException(
304                             "\"" + interfacez + "\" is incompatible with " +
305                                     "already defined element \"" + initialElement +
306                                     "\"");
307                 }
308                 ObjectModelInterfaceImpl initialInterfacez =
309                         (ObjectModelInterfaceImpl) initialElement;
310 
311                 mergeClassifiers(initialInterfacez, interfacez);
312 //                interfacez = initialInterfacez;
313             }
314         }
315         //return interfacez;
316     }
317 
318     /**
319      * Returns the interface corresponding to the given qualified name, or null
320      * if the model contains no interface for this qualified name.
321      *
322      * @param qualifiedInterfaceName -
323      *                               the qualified name of the interface to retrieve.
324      * @return the ObjectModelInterface of the found interface, or null if the
325      * model contains no interface for this qualified name.
326      */
327     @Override
328     public ObjectModelInterface getInterface(String qualifiedInterfaceName) {
329         ObjectModelInterface result = interfaces.get(qualifiedInterfaceName);
330         if (result == null) {
331             if (log.isDebugEnabled()) {
332                 log.debug("Interface " + qualifiedInterfaceName +
333                                   " not found in model");
334             }
335         }
336         return result;
337     }
338 
339     /**
340      * Returns all interfaces defined in this model.
341      *
342      * @return a Collection containing all ObjectModelInterface for this model.
343      * @see ObjectModelInterface
344      */
345     @Override
346     public Collection<ObjectModelInterface> getInterfaces() {
347         return interfaces.values();
348     }
349 
350     public void addEnumeration(ObjectModelEnumerationImpl enumeration) {
351         enumeration.postInit();
352         enumeration.setObjectModelImpl(this);
353         classifiers.put(enumeration.getQualifiedName(), enumeration);
354         enumerations.put(enumeration.getQualifiedName(), enumeration);
355     }
356 
357     @Override
358     public Collection<ObjectModelEnumeration> getEnumerations() {
359         return enumerations.values();
360     }
361 
362     @Override
363     public ObjectModelEnumeration getEnumeration(String qualifiedEnumerationName) {
364         ObjectModelEnumeration result =
365                 enumerations.get(qualifiedEnumerationName);
366         if (result == null) {
367             if (log.isDebugEnabled()) {
368                 log.debug("Enumeration " + qualifiedEnumerationName +
369                                   " not found in model");
370             }
371         }
372         return result;
373     }
374 
375     /**
376      * Returns all comments not lied to a particular model element
377      *
378      * @return a List containing all comments for this model as Strings.
379      */
380     @Override
381     public List<String> getComments() {
382         return comments;
383     }
384 
385     @Override
386     public Set<String> getStereotypes() {
387         Set<String> result = new LinkedHashSet<>();
388         for (Map.Entry<String, String> entry : tagValues.entrySet()) {
389             if ("true".equals(entry.getValue())) {
390                 result.add(entry.getKey());
391             }
392         }
393         return result;
394     }
395 
396     @Override
397     public boolean hasStereotype(String stereotypeName) {
398         return tagValues.containsKey(stereotypeName);
399     }
400 
401     @Override
402     public void addStereotype(String stereotype) {
403         tagValues.put(stereotype, "true");
404     }
405 
406     @Override
407     public void removeStereotype(String stereotype) {
408         tagValues.remove(stereotype);
409     }
410 
411     public void removePackage(String packageName) {
412 
413         for (ObjectModelClass objectModelClass : new LinkedHashSet<>(classes.values())) {
414             if (objectModelClass.getQualifiedName().startsWith(packageName + ".")) {
415                 classes.remove(objectModelClass.getQualifiedName());
416             }
417         }
418         for (ObjectModelInterface objectModelInterface : new LinkedHashSet<>(interfaces.values())) {
419             if (objectModelInterface.getQualifiedName().startsWith(packageName + ".")) {
420                 classes.remove(objectModelInterface.getQualifiedName());
421             }
422         }
423         for (ObjectModelEnumeration objectModelEnumeration : new LinkedHashSet<>(enumerations.values())) {
424             if (objectModelEnumeration.getQualifiedName().startsWith(packageName + ".")) {
425                 classes.remove(objectModelEnumeration.getQualifiedName());
426             }
427         }
428         packages.remove(packageName);
429 
430     }
431 
432     public void removeClass(String className) {
433 
434         classes.remove(className);
435 
436     }
437 
438     public void removeInterface(String interfaceName) {
439         interfaces.remove(interfaceName);
440     }
441 
442     public void removeEnumeration(String enumerationName) {
443         enumerations.remove(enumerationName);
444     }
445 
446     protected void mergePackages(
447             ObjectModelPackageImpl initialPackage,
448             ObjectModelPackageImpl additionalPackage) {
449         Iterator<?> it;
450 
451         String description = "";
452         String sourceDoc = "";
453         if (initialPackage.documentation != null) {
454             description += initialPackage.getDescription();
455             if (initialPackage.documentation.contains("--")) {
456                 sourceDoc += initialPackage.getSourceDocumentation();
457             }
458         }
459         if (additionalPackage.documentation != null) {
460             if (!description.equals("")) {
461                 description += " - ";
462             }
463             description += additionalPackage.getDescription();
464             if (additionalPackage.documentation.contains("--")) {
465                 if (!sourceDoc.equals("")) {
466                     sourceDoc += " - ";
467                 }
468                 sourceDoc += additionalPackage.getSourceDocumentation();
469             }
470         }
471         if (!description.equals("") || !sourceDoc.equals("")) {
472             initialPackage.documentation = description + "--" + sourceDoc;
473         }
474 
475         for (it = additionalPackage.getComments().iterator(); it.hasNext(); ) {
476             String comment = (String) it.next();
477             if (!initialPackage.comments.contains(comment)) {
478                 initialPackage.comments.add(comment);
479             }
480         }
481         for (it = additionalPackage.getStereotypes().iterator(); it.hasNext(); ) {
482             String stereotype = (String) it.next();
483             if (!initialPackage.getStereotypes().contains(stereotype)) {
484                 initialPackage.stereotypes.add(stereotype);
485             }
486         }
487 
488         for (it = additionalPackage.getTagValues().keySet().iterator(); it.hasNext(); ) {
489             String tagName = (String) it.next();
490             if (!initialPackage.getTagValues().containsKey(tagName)) {
491                 initialPackage.tagValues.put(
492                         tagName,
493                         additionalPackage.getTagValue(tagName)
494                 );
495             }
496         }
497     }
498 
499     protected void mergeClassifiers(
500             ObjectModelClassifierImpl initialClazzifier,
501             ObjectModelClassifierImpl additionalClazzifier) {
502         Iterator<?> it;
503 
504         // On n'utilise pas les parsetXXX puisque les post-init sont censés être
505         // déjà faits...
506 
507         // System.out.println("Doc initial : " +
508         // initialClazzifier.documentation);
509         // System.out.println("Doc additional : " +
510         // additionalClazzifier.documentation);
511         String description = "";
512         String sourceDoc = "";
513         if (initialClazzifier.documentation != null) {
514             description += initialClazzifier.getDescription();
515             if (initialClazzifier.documentation.contains("--")) {
516                 sourceDoc += initialClazzifier.getSourceDocumentation();
517             }
518         }
519         if (additionalClazzifier.documentation != null) {
520             if (!description.equals("")) {
521                 description += " - ";
522             }
523             description += additionalClazzifier.getDescription();
524             if (additionalClazzifier.documentation.contains("--")) {
525                 if (!sourceDoc.equals("")) {
526                     sourceDoc += " - ";
527                 }
528                 sourceDoc += additionalClazzifier.getSourceDocumentation();
529             }
530         }
531         if (!description.equals("") || !sourceDoc.equals("")) {
532             initialClazzifier.documentation = description + "--" + sourceDoc;
533         }
534         // System.out.println("Doc after : " + initialClazzifier.documentation);
535 
536         for (it = additionalClazzifier.interfacesRefs.iterator(); it.hasNext(); ) {
537             ObjectModelImplRef interfaceRef = (ObjectModelImplRef) it.next();
538             if (!contains(initialClazzifier.interfacesRefs, interfaceRef)) {
539                 initialClazzifier.interfacesRefs.add(interfaceRef);
540             }
541             initialClazzifier.interfaces = null; // On force ainsi à
542             // regénérer l'objet
543         }
544         for (it = additionalClazzifier.getOperations().iterator(); it.hasNext(); ) {
545             ObjectModelOperationImpl operation = (ObjectModelOperationImpl) it.next();
546             if (!contains(initialClazzifier.getOperations(), operation)) {
547                 initialClazzifier.operations.add(operation);
548             }
549         }
550         for (it = additionalClazzifier.getDependencies().iterator(); it.hasNext(); ) {
551             ObjectModelDependencyImpl dependency = (ObjectModelDependencyImpl) it.next();
552             if (!contains(initialClazzifier.getDependencies(), dependency)) {
553                 initialClazzifier.dependencies.add(dependency);
554             }
555         }
556         for (it = additionalClazzifier.getComments().iterator(); it.hasNext(); ) {
557             String comment = (String) it.next();
558             if (!initialClazzifier.comments.contains(comment)) {
559                 initialClazzifier.comments.add(comment);
560             }
561         }
562         for (it = additionalClazzifier.getStereotypes().iterator(); it.hasNext(); ) {
563             String stereotype = (String) it.next();
564             if (!initialClazzifier.getStereotypes().contains(stereotype)) {
565                 initialClazzifier.addStereotype(stereotype);
566             }
567         }
568 
569         for (it = additionalClazzifier.getTagValues().keySet().iterator(); it.hasNext(); ) {
570             String tagName = (String) it.next();
571             if (!initialClazzifier.getTagValues().containsKey(tagName)) {
572                 initialClazzifier.tagValues.put(
573                         tagName,
574                         additionalClazzifier.getTagValue(tagName)
575                 );
576             }
577         }
578     }
579 
580     /**
581      * This method takes two ObjectModelClassImpl and merges both of them in the
582      * first one
583      *
584      * @param initialClazz    the instance of ObjectModelClassImpl to be modified
585      * @param additionalClazz the instance of ObjectModelClassImpl tu be used for merging
586      */
587     private void mergeClasses(ObjectModelClassImpl initialClazz,
588                               ObjectModelClassImpl additionalClazz) {
589         Iterator<?> it;
590         mergeClassifiers(initialClazz, additionalClazz);
591 
592         for (it = additionalClazz.getAttributes().iterator(); it.hasNext(); ) {
593             ObjectModelAttributeImpl attribute =
594                     (ObjectModelAttributeImpl) it.next();
595             if (!contains(initialClazz.getAttributes(), attribute)) {
596                 initialClazz.attributes.put(attribute.getName(), attribute);
597                 initialClazz.orderedAttributes.add(attribute);
598             }
599         }
600         for (it = additionalClazz.superclassesRefs.iterator(); it.hasNext(); ) {
601             ObjectModelImplRef superclassRef = (ObjectModelImplRef) it.next();
602             if (!contains(initialClazz.superclassesRefs, superclassRef)) {
603                 initialClazz.superclassesRefs.add(superclassRef);
604             }
605             initialClazz.superclasses = null; // On force ainsi à regénérer
606             // l'objet
607         }
608     }
609 
610     private void mergeAssociationClasses(
611             ObjectModelAssociationClassImpl initialAssocClazz,
612             ObjectModelAssociationClassImpl additionalAssocClazz) {
613         mergeClasses(initialAssocClazz, additionalAssocClazz);
614         Iterator<?> it;
615         for (it = additionalAssocClazz.participantsRefs.iterator(); it.hasNext(); ) {
616             ObjectModeImplAssociationClassParticipant participant =
617                     (ObjectModeImplAssociationClassParticipant) it.next();
618             if (!contains(initialAssocClazz.participantsRefs, participant)) {
619                 initialAssocClazz.participantsRefs.add(participant);
620             }
621             initialAssocClazz.participantsAttributes = null; // On force
622             // ainsi à
623             // regénérer
624             // l'objet
625             initialAssocClazz.participantsClassifiers = null; // On force
626             // ainsi à
627             // regénérer
628             // l'objet
629         }
630     }
631 
632     private boolean contains(Collection<ObjectModelAttribute> coll,
633                              ObjectModelAttributeImpl toFind) {
634         for (ObjectModelAttribute attribute : coll) {
635             if (attribute.getName().equals(toFind.getName())) { // Seul le nom
636                 // de l'attribut
637                 // compte
638                 return true;
639             }
640         }
641         return false;
642     }
643 
644     private boolean contains(Collection<?> coll, ObjectModelOperationImpl toFind) {
645         return coll.contains(toFind); // Le equals(...) de
646         // ObjectModelOperationImpl convient
647     }
648 
649     private boolean contains(Collection<?> coll, ObjectModelImplRef toFind) {
650         return coll.contains(toFind); // Le equals(...) de ObjectModelImplRef
651         // convient
652     }
653 
654     public ObjectModelImplTagValue addTagValue(ObjectModelImplTagValue tagValue) {
655         if (tagValue == null) {
656             return new ObjectModelImplTagValue();
657         }
658         tagValues.put(tagValue.getName(), tagValue.getValue());
659         return tagValue;
660     }
661 
662     @Override
663     public Map<String, String> getTagValues() {
664         return tagValues;
665     }
666 
667     @Override
668     public String getTagValue(String tagValue) {
669         return tagValue == null ? null : tagValues.get(tagValue);
670     }
671 
672     @Override
673     public void addTagValue(String tagValue, String value) {
674         String oldValue = getTagValue(tagValue);
675         if (StringUtils.isNotEmpty(oldValue) && !oldValue.equals(value)) {
676             if (log.isWarnEnabled()) {
677                 log.warn("Replace tagValue '" + tagValue + "' (old:" +
678                                  oldValue + ", new: " + value + ")");
679             }
680         }
681         tagValues.put(tagValue, value);
682     }
683 
684     @Override
685     public boolean hasTagValue(String tagValue) {
686         return tagValues.containsKey(tagValue);
687     }
688 
689     @Override
690     public void removeTagValue(String tagvalue) {
691         tagValues.remove(tagvalue);
692     }
693 
694     /**
695      * Get the extension associated to the reference (unique). Create it if not exist.
696      *
697      * @param <O>            object type returned
698      * @param reference      unique corresponding to the extension to get
699      * @param extensionClass class of the extension
700      * @return the object value for the extension
701      * @throws ClassCastException when extensionClass is not valid
702      * @throws RuntimeException   when instantiation problem to create new extension
703      */
704     @Override
705     @SuppressWarnings("unchecked")
706     public <O> O getExtension(String reference, Class<O> extensionClass) throws RuntimeException {
707         if (reference == null) {
708             throw new NullPointerException("reference parameter can not be null in method ObjectModelImpl#getExtension");
709         }
710         if (extensionClass == null) {
711             throw new NullPointerException("extensionClass parameter can not be null in method ObjectModelImpl#getExtension.");
712         }
713         Object object = extensions.get(reference);
714         O result;
715         if (object != null && !extensionClass.isAssignableFrom(object.getClass())) {
716             throw new ClassCastException("Invalid cast for " + extensionClass.getName());
717         }
718         if (object == null) {
719             try {
720                 result = extensionClass.newInstance();
721             } catch (Exception eee) { // IllegalAccessException and InstantiationException
722                 throw new RuntimeException("Unable to create new extension '" + extensionClass.getName() +
723                                                    "' for '" + reference + "'", eee);
724             }
725             extensions.put(reference, result);
726         } else {
727             result = (O) object;
728         }
729         return result;
730     }
731 }