View Javadoc

1   /*
2    * UML2MMBase module.
3    *
4    * The contents of this file are subject to the Mozilla Public License
5    * Version 1.0 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11   * License for the specific language governing rights and limitations
12   * under the License.
13   */
14  
15  package com.finalist.mmbase.uml;
16  
17  import com.finalist.mmbase.umlprofile.MMBaseUMLProfile;
18  import com.finalist.mmbase.umlprofile.MMBaseFieldTypes;
19  import org.andromda.core.common.HTMLAnalyzer;
20  import org.andromda.core.simpleuml.SimpleOOHelper;
21  import org.andromda.core.simpleuml.UMLModelElement;
22  import org.omg.uml.foundation.core.ModelElement;
23  import org.andromda.core.simpleuml.UMLTaggedValue;
24  import org.omg.uml.foundation.core.*;
25  import org.omg.uml.foundation.datatypes.ParameterDirectionKindEnum;
26  import org.omg.uml.foundation.datatypes.VisibilityKind;
27  import org.omg.uml.modelmanagement.Model;
28  
29  import java.io.ByteArrayInputStream;
30  import java.util.*;
31  
32  
33  /***
34   * Helper class to get access to the UML model.
35   *
36   * @author Rudie Ekkelenkamp - Finalist IT Group
37   * @version $Revision: 1.13 $, $Date: 2005/07/12 10:31:41 $
38   */
39  public class MMBaseHelper extends SimpleOOHelper {
40  
41      static final String MODEL_STEREOTYPE = "model";
42      static final int MAX_RECURSION_LEVEL = 10;
43  
44      private static HashMap mmbaseDatabaseSizes = null;
45      private static HashMap mmbaseGuiSizes = null;
46      private static HashMap mmbaseGuiTypes = null;
47      private static HashMap mmbaseDatabaseTypes = null;
48      private static HashMap mmbaseTypes = null;
49  
50      /***
51       * Give access to the association helper.
52       *
53       * @return an MMbase association helper
54       */
55      public MMBaseAssociationHelper getAssociationHelper() {
56          return new MMBaseAssociationHelper(this);
57      }
58  
59      /***
60       * Give access to the relation helper.
61       *
62       * @return an MMBase relation helper
63       */
64      public MMBaseRelationHelper getRelationHelper() {
65          return new MMBaseRelationHelper(this);
66      }
67  
68      /***
69       * Give access to the UML Profile constants
70       *
71       * @return a HasHamp with all constants of this UML profile.
72       */
73      public HashMap getProfile() {
74          return MMBaseUMLProfile.getConstants();
75      }
76  
77      /***
78       * Give acces to the Documentation helper
79       *
80       * @return a MMBaseDocumentationHelper instance
81       */
82      public MMBaseDocumentationHelper getDocumentationHelper() {
83          return new MMBaseDocumentationHelper(this);
84      }
85  
86      /***
87       * This method is needed to trigger code generation for the whole model,
88       * since nog stereotype is set on the model itself.
89       *
90       * @param modelElement the model element
91       * @return A collection with all stereotypes on the modelElement.
92       * @see org.andromda.core.common.ScriptHelper#getStereotypeNames(java.lang.Object)
93       */
94      public Collection getStereotypeNames(Object modelElement) {
95          Collection c = super.getStereotypeNames(modelElement);
96  
97          // If this model element is the model then dynamically add a stereotype
98          if (modelElement instanceof Model) {
99              c.add(MODEL_STEREOTYPE);
100         }
101         return c;
102     }
103 
104     /***
105      * Determine the stereotype that is set on a dependency.
106      *
107      * @param modelElement the model element
108      * @return Empty string if no stereotype has been set. Otherwise the name of the stereotype.
109      */
110     public String getDependencyStereoType(Object modelElement) {
111         String stereotype = "";
112         if (getStereotype(modelElement) == null) {
113             stereotype = "";
114         }
115         else {
116             stereotype = getStereotype(modelElement).toLowerCase();
117         }
118         return stereotype;
119     }
120 
121     /***
122      * Returns the name of a dependency element
123      *
124      * @param object model element
125      * @return fully qualifed name
126      */
127     public String getDependencyName(Object object) {
128         if ((object == null) || !(object instanceof ModelElement)) {
129             return null;
130         }
131         ModelElement modelElement = (ModelElement) object;
132         String fullName = modelElement.getName();
133         return fullName;
134     }
135 
136     /***
137      * Get the current date.
138      *
139      * @return String with the current date.
140      */
141     public final static String getDate() {
142         java.util.Date theDate = new java.util.Date();
143         return theDate.toString();
144     }
145 
146     /***
147      * Convert to Lowercase
148      *
149      * @param arg the argument
150      * @return String converted to lowercase.
151      */
152     public final static String toLowerCase(String arg) {
153         if (arg == null) {
154             return arg;
155         }
156         else {
157             return arg.toLowerCase();
158         }
159     }
160 
161     /***
162      * Convert to Uppercase
163      *
164      * @param arg the argument
165      * @return String converted to uppercase.
166      */
167     public final static String toUpperCase(String arg) {
168         if (arg == null) {
169             return arg;
170         }
171         else {
172             return arg.toUpperCase();
173         }
174     }
175 
176     /***
177      * Determine the fully qualified class name.
178      *
179      * @param packageName package name
180      * @param className   class name
181      * @return fully qualified class name.
182      */
183     publicong> final static String toClassName(String packageName, String className) {
184         String result = null;
185         if (className == null) {
186             return null;
187         }
188         else {
189             >if (packageName == null || packageName.equals("")) {
190                 result = org.andromda.core.common.StringUtilsHelper.upperCaseFirstLetter(className);
191             }
192             else {
193                 result = packageName + "." + org.andromda.core.common.StringUtilsHelper.upperCaseFirstLetter(className);
194             }
195             return result;
196         }
197     }
198 
199     /***
200      * Returns the name of a model element fully qualified by the
201      * name of the package that contains it.
202      *
203      * @param object model element
204      * @return fully qualifed name
205      */
206     public String getOperationType(Object object) {
207         if ((object == null) || !(object instanceof Operation)) {
208             System.out.println("Not a valid object.");
209             return null;
210         }
211         Operation operation = (Operation) object;
212         Collection parms = operation.getParameter();
213         for (Iterator i = parms.iterator(); i.hasNext();) {
214             Parameter p = (Parameter) i.next();
215             if (ParameterDirectionKindEnum.PDK_RETURN.equals(p.getKind())) {
216                 return p.getType().getName();
217             }
218         }
219         return "";
220     }
221 
222 
223     /***
224      * Returns a Collection of MMBaseInterfaceVO with all attributes of
225      * the specified class
226      *
227      * @param object      model element
228      * @param visibilitiy the visibility
229      * @return fully qualifed name
230      */
231     public Collection getClassAttributes(Object object, String visibilitiy) {
232         ArrayList list = new ArrayList();
233         // First get a list of attributes in the class.
234         for (Iterator iterator = this.getAttributes(object).iterator(); iterator.hasNext();) {
235             Attribute att = (Attribute) iterator.next();
236             String name = att.getName();
237             if (name != null && !name.startsWith("lnk")) {
238                 // Together generates lnk... attributes for associations. We don't want them.
239                 // we check on the attribute name, but this is somewhat of a hack...
240                 String documentation = getJavaDoc(att);
241                 Collection tags = getTaggedValues(att);
242                 Collection stereotypes = getStereotypeNames(att);
243                 String viz = att.getVisibility().toString().toLowerCase();
244 
245                 // String type = findFullyQualifiedName(att.getType());
246                 // For MMBase types, nu package name is needed.
247                 
248                 Classifier attType = att.getType();
249                 if (attType == null) {
250                     throw new NullPointerException("Attribute type missing for " + name);
251                 }
252                 String type = attType.getName();
253                 String defaultValue = null;
254                 if (att.getInitialValue() != null) {
255                     defaultValue = att.getInitialValue().getBody();
256                 }
257                 viz = normalizeVisibility(viz);
258                 MMBaseAttributeVo vo = createMMBaseAttribute(
259                         tags, name, type, documentation, viz, stereotypes, defaultValue);
260                 if (visibilityMatch(viz, visibilitiy)){
261                     list.add(vo);
262                 }
263             }
264         }
265         return list;
266     }
267 
268     /* in uml visibility is modeled with vk_... names. normalize these names to private, protected and public */
269     private static String normalizeVisibility(String viz) {
270         String defaultViz = "private";
271         if (viz == null) {
272             return defaultViz;
273         }
274         if (viz.equals("vk_private")) {
275             return "private";
276         }
277         else if (viz.equals("vk_protected")) {
278             return "protected";
279         }
280         else if (viz.equals("vk_public")) {
281             return "public";
282         }
283         return defaultViz;
284     }
285 
286 
287     /***
288      * Get a list of all Classifier objects (superclasses) for a given
289      * Classifier object. This will allow you to get to
290      *
291      * @param object Classifier
292      * @param level  Restrict the recursion level.
293      * @return Collection of Classifiers this classefier extends.
294      */
295     public Collection getAllGeneralizations(Object object, int level) {
296 
297         // To avoid infinite loops:
298         if (level >= MAX_RECURSION_LEVEL) {
299             return new ArrayList();
300         }
301         if ((object == null) || !(object instanceof Classifier)) {
302             System.out.println("Not a valid object.");
303             return new ArrayList();
304         }
305         GeneralizableElement element = (GeneralizableElement) object;
306         Collection gens = element.getGeneralization();
307         // Collection gens = model.getCore().getAChildGeneralization().getGeneralization(element);
308         if (gens == null || gens.size() == 0) {
309             // No more generalizations.
310             return new ArrayList();
311         }
312         Iterator i = gens.iterator();
313         Generalization gel = null;
314         if (i == null) {
315             return new ArrayList();
316         }
317         if (i.hasNext()) {
318             gel = (Generalization) i.next();
319         }
320         // This is the new one.
321 
322         Object newObject = gel.getParent();
323         // Get the superclasses as well by calling the method recrsively.
324         Collection theList = (getAllGeneralizations(newObject, level + 1));
325         ArrayList newList = new ArrayList();
326         newList.add(newObject);
327         // Prepend the object.
328         newList.addAll(theList);
329         return newList;
330     }
331 
332     /***
333      * Returns the name of the super class
334      *
335      * @param object model element
336      * @return class name
337      */
338     public String getGeneralizationName(Object object) {
339         Collection allGens = getAllGeneralizations(object, 0);
340         if (allGens.size() > 0) {
341             ModelElement modelElement = (ModelElement) ((ArrayList) allGens).get(0);
342             return modelElement.getName();
343         }
344         return null;
345     }
346 
347     /***
348      * Returns a Collection of MMBaseInterfaceVO with all attributes of
349      * the interfaces the class implements
350      * This has to be implemented. We get a class cast exception for
351      * model.getCore().getAChildGeneralization().getGeneralization(element).iterator();
352      *
353      * @param object      model element
354      * @param visibilitiy the visibility
355      * @return fully qualifed name
356      */
357     public Collection getGeneralizationAttributes(Object object, String visibilitiy) {
358         Collection allGens = this.getAllGeneralizations(object, 0);
359         if (allGens == null || allGens.size() == 0) {
360             return new ArrayList();
361         }
362         Collection attributes = new ArrayList();
363         // Now iterate over all generalizing elements and get their attributes.
364         for (Iterator iterator = allGens.iterator(); iterator.hasNext();) {
365             Object o = iterator.next();
366             attributes.addAll(getAllAttributes(o, "true", "true", "true", visibilitiy));
367         }
368         return attributes;
369     }
370 
371     /***
372      * Helper class for mapping UML attributes to MMBase specific settings.
373      *
374      * @return MMBaseAttributeVo
375      */
376     private MMBaseAttributeVo createMMBaseAttribute(Collection tags, String name, String type, String documentation, String viz, Collection stereotypes, String defaultValue) {
377        
378        int stringGuiSize;
379         // If the type is an optionList, set the type to string.
380         String optionListDefinition = null;
381         if (isOptionList(type)) {
382             optionListDefinition = type;
383             type = "string";
384         }
385         String dbType = getMMBaseDatabaseType(type);
386         boolean system =("true".equals(this.findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_SYSTEM)));
387         String minSize = this.findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MINSIZE);
388         String maxSize = this.findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MAXSIZE);
389         String prompt = this.findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_PROMPT);
390         if (prompt != null) {
391             prompt = getDocumentationHelper().getXML(prompt);
392         }
393         String dbSize = getMMBaseDatabaseSize(type);
394         String fieldType = null;
395 
396         if (maxSize != null) {
397             try {
398                 int sizeInt = Integer.parseInt(maxSize);
399                 // If we get here, the maxsize has been set correctly, so use it.
400                 // In case of a String, also use it for the database size.
401                 if (dbType.equalsIgnoreCase(MMBaseUMLProfile.MMBASE_STRING_TYPE) || dbType.equalsIgnoreCase(MMBaseUMLProfile.MMBASE_BYTE_TYPE)) {
402                     // In this case we want to set the db size to the specified size.
403                     dbSize = maxSize;
404                     try{
405                        stringGuiSize = new Integer(MMBaseFieldTypes.STRING_GUI_SIZE).intValue();
406                     }catch (NumberFormatException e){
407                        System.out.println("property with name 'string.gui.size' is not an integer. Using default.");
408                        stringGuiSize = MMBaseUMLProfile.MAX_SIZE_TEXT_FIELD;
409                     }
410                     // Check if size > gui size. In that case, we need a text area, instead of a line.
411                     // The only exception is for the fieldType html.
412                     if (sizeInt > stringGuiSize && !type.equalsIgnoreCase(MMBaseUMLProfile.MMBASE_HTML_TYPE)) {
413                      // In this case we want to set a "text" field type.
414                      // Otherwise a input line will be generated.
415                      fieldType = "text";
416                     }
417                 }
418             }
419             catch (Exception e) {
420                 System.out.println("Tagged value maxsize is NOT an integer: " + maxSize);
421                 System.out.println("Using the default value for this type now....");
422                 maxSize = getMMBaseGuiSize(type);
423             }
424         }
425 
426         if (dbSize == null) {
427             // If the dbSize has not been set, get the default size for this type.
428             dbSize = getMMBaseDatabaseSize(type);
429         }
430         if (prompt == null || "".equals(prompt)) {
431             prompt = name;
432         }
433 
434         return new MMBaseAttributeVo(name, type, stereotypes, documentation, viz, dbType, prompt,
435                 dbSize, minSize, maxSize, fieldType, optionListDefinition, defaultValue, system);
436     }
437 
438     /***
439      * Returns a Collection of MMBaseInterfaceVO with all attributes of
440      * the interfaces the class implements
441      * problem: unexpected class cast exceptions on certain relation classes...
442      *
443      * @param object      model element
444      * @param visibilitiy the visibility
445      * @return fully qualifed name
446      */
447     public Collection getInterfaceAttributes(Object object, String visibilitiy) {
448         ArrayList list = new ArrayList();
449         if ((object == null) || !(object instanceof Classifier)) {
450             System.out.println("Not a valid object.");
451             return list;
452         }
453          //the below line causes mysterious class cast exceptions
454         Collection interfaces = this.getAbstractions(object);
455         if (interfaces == null) {
456             return list;
457         }
458         for (Iterator iterator = interfaces.iterator(); iterator.hasNext();) {
459             Object inf = iterator.next();
460             // Now get all operations in this interface. They will be marked as an attribute.
461             Collection ops = getOperations(inf);
462             for (Iterator itr = ops.iterator(); itr.hasNext();) {
463                 Operation op = (Operation) itr.next();
464                 Collection tags = getTaggedValues(op);
465                 String documentation = getJavaDoc(op);
466                 String name = getName(op);
467                 String type = getOperationType(op);
468                 String viz = op.getVisibility().toString().toLowerCase();
469                 Collection stereotypes = getStereotypeNames(op);
470                 viz = normalizeVisibility(viz);
471 
472                 MMBaseAttributeVo vo = createMMBaseAttribute(tags, name, type, documentation, viz, stereotypes, "");
473 
474                 if (visibilityMatch(viz, visibilitiy) ) {
475                     list.add(vo);
476                 }
477             }
478 
479             // Now get all attributes in this interface. They will also be marked as an attribute.
480             Collection atts = this.getAttributes(inf);
481             for (Iterator itr = atts.iterator(); itr.hasNext();) {
482                 Attribute att = (Attribute) itr.next();
483                 Collection tags = getTaggedValues(att);
484                 String documentation = getJavaDoc(att);
485                 String name = getName(att);
486                 String type = att.getType().getName();
487                 String viz = att.getVisibility().toString().toLowerCase();
488                 Collection stereotypes = getStereotypeNames(att);
489                 viz = normalizeVisibility(viz);
490                 MMBaseAttributeVo vo = createMMBaseAttribute(tags, name, type, documentation, viz, stereotypes, "");
491                 if (visibilityMatch(viz, visibilitiy) ) {
492                     list.add(vo);
493                 }
494             }
495         }
496         return list;
497     }
498 
499 
500     /***
501      * Returns a Collection of MMBaseInterfaceVO with all attributes related to a class:
502      * Class attributes, Interface attributes..
503      *
504      * @param object          model element
505      * @param clazz           should the attributes of the class itself also be included? Default is true.
506      * @param interfazes      should the attributes of the interface also be included? Default is false.
507      * @param generalizations should the attributes of super classes also be included? The default is true.
508      * @param visibilitiy     specify the visiblity of the attributes that should be collected. If null,
509      *                        all attributes are returned. Other valueas are: public, private and protected.
510      * @return fully qualifed name
511      */
512     public Collection getAllAttributes(Object object, String clazz, String interfazes, String generalizations, String visibilitiy) {
513         ArrayList list = new ArrayList();
514         if (generalizations != null && generalizations.equalsIgnoreCase("true")) {
515             list.addAll(getGeneralizationAttributes(object, visibilitiy));
516         }
517         if (interfazes != null && interfazes.equalsIgnoreCase("true")) {
518             list.addAll(getInterfaceAttributes(object, visibilitiy));
519         }
520         if (clazz != null && clazz.equalsIgnoreCase("true")) {
521             list.addAll(getClassAttributes(object, visibilitiy));
522         }
523         return list;
524     }
525 
526     /***
527      * Get a list of all attributes in the class and interface.
528      *
529      * @param object the object
530      * @return Collection of  MMBaseAttributeVo objects.
531      */
532     public Collection getAllAttributes(Object object) {
533         return getAllAttributes(object, "true", "true", "false", "");
534     }
535 
536     /***
537      * @param relationName    Name of the relation for which all attributes should be returned.
538      * @param clazz           do we want the class attributes? true or false.
539      * @param interfazes      do we want the interface attributes? true or false.
540      * @param generalizations do we want the generatlization attributes? true or false.
541      * @param visibilitiy     threshold for the visibility. private will get all attributes.
542      * @return Collection of  MMBaseAttributeVo objects.
543      */
544     public Collection getAllRelationAttributes(String relationName, String clazz, String interfazes, String generalizations, String visibilitiy) {
545         ArrayList list = new ArrayList();
546         Object relationObject = null;
547         if (relationName == null) {
548             return list;
549         }
550         Collection modelElements = this.getModelElements();
551         for (Iterator iterator = modelElements.iterator(); iterator.hasNext();) {
552             Object o = iterator.next();
553             if (o != null && this.getName(o) != null && this.getName(o).equals(relationName)) {
554                 if (this.getStereotype(o) != null && this.getStereotype(o).equals(MMBaseUMLProfile.STEREOTYPE_CLASS_RELATION)) {
555                     relationObject = o;
556                     break;
557                 }
558             }
559         }
560         if (relationObject == null) {
561             return list;
562         }
563 
564         if (generalizations != null && generalizations.equalsIgnoreCase("true")) {
565             list.addAll(getGeneralizationAttributes(relationObject, visibilitiy));
566         }
567         /***
568          * Not needed for relations, but gives a cast exception also.....
569          if (interfazes != null && interfazes.equalsIgnoreCase("true")) {
570          list.addAll(getInterfaceAttributes(relationObject, visibilitiy));
571          }
572          */
573 
574         if (clazz != null && clazz.equalsIgnoreCase("true")) {
575             list.addAll(getClassAttributes(relationObject, visibilitiy));
576         }
577         return list;
578     }
579 
580     /***
581      * Same as getModelElements, but now the model elements are sorted by name.
582      *
583      * @return Collection with sorted model elements of the type Classifer.
584      */
585     public Collection getSortedModelClassifiers() {
586         HashMap map = new HashMap();
587         Collection modelElements = this.getModelElements();
588         for (Iterator iterator = modelElements.iterator(); iterator.hasNext();) {
589             Object o = iterator.next();
590             if (MMBaseUMLProfile.STEREOTYPE_CLASS_MMBASE.equals(this.getStereotype(o))) {
591                 if ((o instanceof Classifier) && (getName(o) != null)) {
592                     map.put(getName(o), o);
593                 }
594             }
595 
596         }
597         return sortValuesByKeys(map);
598     }
599 
600     /***
601      * Get all model elements with the Relation stereotype.
602      *
603      * @return Collection with sorted model elements.
604      */
605     public Collection getSortedRelationElements() {
606         HashMap map = new HashMap();
607         Collection modelElements = this.getModelElements();
608         for (Iterator iterator = modelElements.iterator(); iterator.hasNext();) {
609             Object o = iterator.next();
610             if (MMBaseUMLProfile.STEREOTYPE_CLASS_RELATION.equals(this.getStereotype(o))) {
611                 if ((o instanceof Classifier) && (getName(o) != null)) {
612                     map.put(getName(o), o);
613                 }
614             }
615 
616         }
617         return sortValuesByKeys(map);
618     }
619 
620     /***
621      * Get the name of an attribute
622      *
623      * @param object the object
624      * @return Attribute name.
625      */
626     public String getAttributeName(Object object) {
627         if (object instanceof MMBaseAttributeVo) {
628             return ((MMBaseAttributeVo) object).getAttributeName();
629         }
630         else {
631             return null;
632         }
633     }
634 
635 
636     /***
637      * Get the type of an attribute.
638      *
639      * @param object the object
640      * @return Attribute type.
641      */
642     public String getAttributeType(Object object) {
643         if (object instanceof MMBaseAttributeVo) {
644             return ((MMBaseAttributeVo) object).getAttributeType();
645         }
646         else {
647             return null;
648         }
649     }
650 
651     /***
652      * Get the type of an attribute.
653      *
654      * @param object the object
655      * @return Attribute type.
656      */
657     public boolean getAttributeRequired(Object object) {
658         if (object instanceof MMBaseAttributeVo) {
659             return ((MMBaseAttributeVo) object).isRequired();
660         }
661         else {
662             return false;
663         }
664     }
665 
666     /***
667      * Get if attribute is required
668      *
669      * @param object the object
670      * @return true if attribute is required.
671      */
672     public boolean getAttributeStereoType(Object object) {
673         if (object instanceof MMBaseAttributeVo) {
674             return ((MMBaseAttributeVo) object).isRequired();
675         }
676         else {
677             return false;
678         }
679     }
680 
681     /***
682      * Get documentation set on an attribute.
683      *
684      * @param object the object
685      * @return Doucmentation.
686      */
687     public String getAttributeDocumentation(Object object) {
688         if (object instanceof MMBaseAttributeVo) {
689             return ((MMBaseAttributeVo) object).getDocumentation();
690         }
691         else {
692             return null;
693         }
694     }
695 
696     /***
697      * Get the javadoc from a model element and strip all paragraphs.
698      * First check if there is a tagged value with the name javadoc.
699      * Next check the javadoc model element.
700      *
701      * @param value UML Model element
702      * @return String with the javadoc tag.
703      */
704     public String getJavaDoc(Object value) {
705         String javadoc = null;
706         if (value instanceof String) {
707             javadoc = (String) value;
708         }
709         else if (value instanceof UMLTaggedValue) {
710             javadoc = ((UMLTaggedValue) value).getValue();
711         }
712         else if (value instanceof ModelElement) {
713             ModelElement el = (ModelElement) value;
714             if (el != null) {
715                 // First check the tagged values.
716                 Collection tags = getTaggedValues(value);
717                 javadoc = findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_DOCUMENTATION);
718                 if (javadoc == null) {
719                     javadoc = "";
720                     // Now check the uml comment elements.
721                     Collection comments = el.getComment();
722                     if (comments != null && !comments.isEmpty()) {
723                         String commentString = null;
724                         Iterator commentIt = comments.iterator();
725                         while (commentIt.hasNext()) {
726                             Comment comment = (Comment) commentIt.next();
727                             commentString = comment.getBody();
728                             if (commentString == null) {
729                                 commentString = comment.getName();
730                             }
731                             if (commentString != null) {
732                                 commentString = commentString.trim();
733                                 if (commentString != null) {
734                                     javadoc += commentString;
735                                 }
736                             }
737                         }
738                         if (javadoc == null) {
739                             return "";
740                         }
741                     }
742                 }
743             }
744         }
745         else {
746             return "";
747         }
748         return javaDocToText(javadoc).trim();
749     }
750 
751     /***
752      * Convert javadoc text to plaint text.
753      *
754      * @param value object with HTML formatting. Can be a String or a Tagged value.
755      * @return String withous P tags.
756      */
757     public final static String javaDocToText(Object value) {
758         if (value == null) {
759             return "";
760         }
761         String javadoc = null;
762         if (value instanceof String) {
763             javadoc = (String) value;
764         }
765         else if (value instanceof UMLTaggedValue) {
766             javadoc = ((UMLTaggedValue) value).getValue();
767         }
768         else {
769             return "";
770         }
771         String result = "";
772         try {
773             Collection col = new HTMLAnalyzer().htmlToParagraphs(javadoc);
774             if (col.size() == 0) {
775                 result = javadoc;
776             }
777             Iterator it = col.iterator();
778             while (it.hasNext()) {
779                 String line = it.next().toString().trim();
780                 if (line != null) {
781                     result += line;
782                     result += "\n";
783                 }
784             }
785         }
786         catch (Exception e) {
787             e.printStackTrace();
788             return "";
789         }
790         if (result == null) {
791             result = "";
792         }
793         return result;
794     }
795 
796 
797     /***
798      * Return the type in lowercase and remove any package names.
799      *
800      * @param type the type
801      * @return normalized mmbase type.
802      */
803     public static String getNormalizedMMBaseType(String type) {
804 
805         // Define all allowed mmbase types.
806         if (mmbaseTypes == null) {
807             mmbaseTypes = new HashMap();
808             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, null);
809             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, null);
810             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_DOUBLE_TYPE, null);
811             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, null);
812             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, null);
813             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_INT_TYPE, null);
814             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_LONG_TYPE, null);
815             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, null);
816             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, null);
817             mmbaseTypes.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, null);
818         }
819 
820         String passedType = type;
821         if ((type == null) || (type.equals(""))) {
822             System.out.println("WARNING: Invalid MMBase type specified: " + passedType);
823             System.out.println("Using a string as default type.");
824             return "string";
825         }
826         else {
827             int index = 0;
828             index = type.lastIndexOf(".");
829             if (index > 0) {
830                 type = type.substring(index + 1);
831             }
832             type = type.toLowerCase();
833 
834             // Now check if it is a valid type:
835             if (mmbaseTypes.containsKey(type)) {
836                 return type;
837             }
838             else {
839                 System.out.println("WARNING: Invalid MMBase type specified: " + passedType);
840                 System.out.println("Using a string as default type.");
841                 return "string";
842             }
843         }
844     }
845 
846     /***
847      * Map a type to a MMBase Database type.
848      *
849      * @param type the type
850      * @return Database type as a string.
851      */
852     public synchronized static String getMMBaseDatabaseType(String type) {
853         if (mmbaseDatabaseTypes == null) {
854             mmbaseDatabaseTypes = new HashMap();
855             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, MMBaseFieldTypes.HTML_DB_TYPE);
856             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, MMBaseFieldTypes.FLOAT_DB_TYPE);
857             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_DOUBLE_TYPE, MMBaseFieldTypes.DOUBLE_DB_TYPE);
858             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, MMBaseFieldTypes.STRING_DB_TYPE);
859             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, MMBaseFieldTypes.INTEGER_DB_TYPE);
860             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_INT_TYPE, MMBaseFieldTypes.INTEGER_DB_TYPE);
861             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_LONG_TYPE, MMBaseFieldTypes.LONG_DB_TYPE);
862             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, MMBaseFieldTypes.DATE_DB_TYPE);
863             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, MMBaseFieldTypes.BOOLEAN_DB_TYPE);
864             mmbaseDatabaseTypes.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, MMBaseFieldTypes.BYTE_DB_TYPE);
865         }
866         String theType = getNormalizedMMBaseType(type);
867         return (String) mmbaseDatabaseTypes.get(theType);
868     }
869 
870     /***
871      * Map the type to a GUI type
872      *
873      * @param type the type
874      * @return gui type
875      */
876     public synchronized static String getMMBaseGuiType(String type) {
877         if (mmbaseGuiTypes == null) {
878             mmbaseGuiTypes = new HashMap();
879             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, MMBaseFieldTypes.HTML_GUI_TYPE);
880             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, MMBaseFieldTypes.FLOAT_GUI_TYPE);
881             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_DOUBLE_TYPE, MMBaseFieldTypes.DOUBLE_GUI_TYPE);
882             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, MMBaseFieldTypes.STRING_GUI_TYPE);
883             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, MMBaseFieldTypes.INTEGER_GUI_TYPE);
884             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_INT_TYPE, MMBaseFieldTypes.INTEGER_GUI_TYPE);
885             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_LONG_TYPE, MMBaseFieldTypes.LONG_GUI_TYPE);
886             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, MMBaseFieldTypes.DATE_GUI_TYPE);
887             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, MMBaseFieldTypes.BOOLEAN_GUI_TYPE);
888             mmbaseGuiTypes.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, MMBaseFieldTypes.BYTE_GUI_TYPE);
889         }
890         String theType = getNormalizedMMBaseType(type);
891         return (String) mmbaseGuiTypes.get(theType);
892     }
893 
894 
895     /***
896      * Map the type on a database size.
897      *
898      * @param type the type
899      * @return database size as a String
900      */
901     public final synchronized static String getMMBaseDatabaseSize(String type) {
902         if (mmbaseDatabaseSizes == null) {
903             mmbaseDatabaseSizes = new HashMap();
904             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, MMBaseFieldTypes.HTML_DB_SIZE);
905             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, "1");
906             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_DOUBLE_TYPE, "1");
907             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, MMBaseFieldTypes.STRING_DB_SIZE);
908             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, "1");
909             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_INT_TYPE, "1");   // 16 bits signed: -2147483648 t/m +2147483647
910             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_LONG_TYPE, "1");  // 64 bits signed: -9223372036854775808 t/m +9223372036854775807
911             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, "1");
912             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, "1");
913             mmbaseDatabaseSizes.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, MMBaseFieldTypes.BYTE_DB_SIZE);   // Used for images etc. Should be big.
914         }
915         String theType = getNormalizedMMBaseType(type);
916         return (String) mmbaseDatabaseSizes.get(theType);
917     }
918 
919 
920     /***
921      * Map the type on a database size.
922      *
923      * @param type the type
924      * @return database size as a String
925      */
926     public final synchronized static String getMMBaseGuiSize(String type) {
927         if (mmbaseGuiSizes == null) {
928             mmbaseGuiSizes = new HashMap();
929             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, MMBaseFieldTypes.HTML_GUI_SIZE);
930             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, MMBaseFieldTypes.FLOAT_GUI_SIZE);
931             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_DOUBLE_TYPE, MMBaseFieldTypes.DOUBLE_GUI_SIZE);
932             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, MMBaseFieldTypes.STRING_GUI_SIZE);
933             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, MMBaseFieldTypes.INTEGER_GUI_SIZE);
934             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_INT_TYPE, MMBaseFieldTypes.INTEGER_GUI_SIZE);   // 16 bits signed: -2147483648 t/m +2147483647
935             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_LONG_TYPE, MMBaseFieldTypes.LONG_GUI_SIZE);
936             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, MMBaseFieldTypes.DATE_GUI_SIZE);
937             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, MMBaseFieldTypes.BOOLEAN_GUI_SIZE);
938             mmbaseGuiSizes.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, MMBaseFieldTypes.BYTE_GUI_SIZE);   // Not used in a gui.
939         }
940         String theType = getNormalizedMMBaseType(type);
941         return (String) mmbaseGuiSizes.get(theType);
942     }
943 
944     /***
945      * Check if the passed value matches the visibility.
946      * If the value is a null or an empty string, there is always a match.
947      * Other matches are:
948      * <p/>
949      * [vk_]private matches [vk_]private
950      * [vk_]protected matches [vk_]protected
951      * [vk_]public matches [vk_]public
952      *
953      * @param value      the value to check
954      * @param visibility the required visibility: private, protected or public, if set to null or "", everything will match.
955      * @return
956      */
957     private boolean visibilityMatch(String value, String visibility) {
958         if (visibility == null || visibility.equals("")) {
959             return true;
960         }
961         if (value == null) {
962             value = "";
963         }
964         else {
965             value = value.toLowerCase();
966         }
967         visibility = visibility.toLowerCase();
968         if (value.equals("private") && visibility.equals("private")) {
969             return true;
970         }
971         if (value.equals("protected") && visibility.equals("protected")) {
972             return true;
973         }
974         if (value.equals("public") && visibility.equals("public")) {
975             return true;
976         }
977         return false;
978     }
979 
980     /***
981      * Checks if the ModelElement is a UML Package.
982      *
983      * @param modelElement The name of the ModelElement.
984      * @return A boolean that specifies if the ModelElement is a package.
985      */
986     public boolean isPackage(Object modelElement) {
987         boolean returnValue = false;
988         if (modelElement != null) {
989             if (modelElement instanceof org.omg.uml.modelmanagement.UmlPackage) {
990                 return true;
991             }
992         }
993         return returnValue;
994     }
995 
996 
997     /***
998      * Checks if the ModelElement with the specified name is indeed an OptionList *
999      *
1000      * @param name The name of the ModelElement.
1001      * @return A boolean that specifies if the ModelElement is an OptionList.
1002      */
1003     protected boolean isOptionList(String name) {
1004         boolean returnValue = false;
1005         if (name != null) {
1006             Collection modelElements = this.getModelElements();
1007             if (modelElements != null) {
1008                 for (Iterator iterator = modelElements.iterator(); iterator.hasNext();) {
1009                     ModelElement modelElement = (ModelElement) iterator.next();
1010                     if (name.equals(modelElement.getName())
1011                             && MMBaseUMLProfile.STEREOTYPE_CLASS_OPTIONLIST.equalsIgnoreCase(this.getStereotype(modelElement))) {
1012                         returnValue = true;
1013                     }
1014                 }
1015             }
1016         }
1017         return returnValue;
1018     }
1019 
1020     /***
1021      * @param o UMLModelElement object with the stereotype "OptionList"
1022      *          containing information about the list.
1023      * @return A collection of MMBaseOptionVo's cotaining the options.
1024      */
1025     public Collection getOptions(Object o) {
1026         Collection options = new ArrayList();
1027         if (o instanceof UMLModelElement) {
1028             UMLModelElement m = (UMLModelElement) o;
1029             String doc = this.getJavaDoc(o);
1030             ArrayList keyList = new ArrayList();
1031 
1032             Properties p = new Properties();
1033             try {
1034                 StringTokenizer s = new StringTokenizer(doc, "\n", false);
1035                 while (s.hasMoreElements()) {
1036                     String option = ((String) s.nextElement()).trim();
1037                     if (!"".equals(option)) {
1038                         String theOption = option.substring(0, option.indexOf("=")).trim();
1039                         p.load(new ByteArrayInputStream(option.getBytes()));
1040                         keyList.add(theOption);
1041                     }
1042                 }
1043             }
1044             catch (Exception e) {
1045                 System.out.println("Error while parsing the optionlist data.");
1046             }
1047 
1048             MMBaseOptionVo mmbaseOptionVo;
1049 
1050             for (Iterator it3 = keyList.iterator(); it3.hasNext();) {
1051                 String option = (String) it3.next();
1052                 if (!"".equals(option)) {
1053                     String optionValue = p.getProperty(option);
1054                     // Make sure we can parse the value as XML
1055                     optionValue = getDocumentationHelper().getXML(optionValue);
1056                     mmbaseOptionVo = new MMBaseOptionVo(option.toString(), optionValue);
1057                     options.add(mmbaseOptionVo);
1058                 }
1059             }
1060 
1061         }
1062         return options;
1063     }
1064 
1065 
1066     /***
1067      * Sort a HashMap based on it's keys and return a Collection with the values
1068      *
1069      * @param map Hashamp with String object pairs that has to be sorted.
1070      * @return Collection of sorted objects based on the keys in the HashMap.
1071      */
1072     public static Collection sortValuesByKeys(HashMap map) {
1073         ArrayList orderedResultList = new ArrayList();
1074         ArrayList resultList = new ArrayList(map.keySet());
1075         Collections.sort(resultList);
1076         for (int i = 0; i < resultList.size(); i++) {
1077             orderedResultList.add(map.get(resultList.get(i)));
1078         }
1079         return orderedResultList;
1080     }
1081 
1082     /***
1083      * Get a list with the names of the basic relation builders needed by MMBase.
1084      *
1085      * @return list of Strings with the relation builder names.
1086      */
1087     public static Collection getBasicRelationBuilders() {
1088         ArrayList list = new ArrayList();
1089         list.add(MMBaseUMLProfile.BASIC_INSREL_RELATION_BUILDER);
1090         list.add(MMBaseUMLProfile.BASIC_POSREL_RELATION_BUILDER);
1091         return list;
1092     }
1093 
1094     /***
1095      * Get a list with the names of the basic builders needed by MMBase.
1096      *
1097      * @return list of Strings with the builder names.
1098      */
1099     public static Collection getBasicBuilders() {
1100         ArrayList list = new ArrayList();
1101         list.add(MMBaseUMLProfile.BASIC_IMAGES_BUILDER);
1102         list.add(MMBaseUMLProfile.BASIC_ATTACHMENTS_BUILDER);
1103         list.add(MMBaseUMLProfile.BASIC_URLS_BUILDER);
1104         return list;
1105     }
1106 
1107     /***
1108      * Returns the tagged value of title on a class in XML format
1109      *
1110      * @param object model element
1111      * @return value of the title tagged value, or null if not set.
1112      */
1113     public String getClassTitle(Object object) {
1114         Collection tags = getTaggedValues(object);
1115         String title = findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_CLASS_TITLE);
1116         if (title != null) {
1117             title = javaDocToText(title);
1118             title = getDocumentationHelper().getXML(title);
1119         }
1120         return title;
1121     }
1122 
1123     /***
1124      * Returns the tagged value of title on a class
1125      *
1126      * @param object model element
1127      * @return value of the title tagged value, or null if not set.
1128      */
1129     public String getClassSubTitle(Object object) {
1130         Collection tags = getTaggedValues(object);
1131         String subTitle = findTagValue(tags, MMBaseUMLProfile.TAGGED_VALUE_CLASS_SUBTITLE);
1132         if (subTitle != null) {
1133             subTitle = javaDocToText(subTitle);
1134             subTitle = getDocumentationHelper().getXML(subTitle);
1135         }
1136         return subTitle;
1137     }
1138     
1139     /***
1140     * Function to test the 'system' flaf on an MMBaseAttributeVo instance.
1141     *
1142     * @param attribute must be instance of MMBaseAttributeVo
1143     **/
1144     public boolean isSystemAttribute(Object attribute){
1145       if (attribute instanceof MMBaseAttributeVo == false) return false;
1146       return ((MMBaseAttributeVo)attribute).isSystem();
1147     }
1148     
1149     /***
1150     * Function to test visibility on a ModelElement.
1151     * 
1152     * @param modelElement is the object to be checked
1153     * @param visibility is the level of visibility it can be checked on
1154     * [private|protected|package|public]
1155     * @return true or false;
1156     **/
1157     public boolean checkModelElementVisibility (Object modelElement, String visibility){
1158       if("public,private,package,protected".indexOf(visibility.toLowerCase()) == -1) return false;
1159       if (modelElement instanceof ModelElement == false ) return false;
1160       VisibilityKind kind  = ((ModelElement)modelElement).getVisibility();
1161       if (kind == null) return false;   //this should neven happen...
1162       String vis = kind.toString().toLowerCase();
1163       vis = normalizeVisibility(vis);
1164       return visibilityMatch(vis, visibility);
1165     }
1166     
1167     /***
1168     * Tries to find a model object of given name.
1169     *
1170     * @param elementName of model object
1171     * @return the corresponding model object or null if none was found    
1172     **/
1173     private Object getModelElement(String elementName){
1174       Iterator i = getModelElements().iterator();
1175       Object object;
1176       while (i.hasNext()){
1177          object =  i.next();
1178          if (((ModelElement)object).getName()!= null 
1179             && ((ModelElement)object).getName().equals(elementName)){
1180             return object;
1181          }else{
1182             if(object == null) System.out.println("modelElement is null");
1183          }
1184       }
1185       return null;
1186     }
1187     
1188 /*    
1189     ***
1190     * Returns a list with the names of optionlists occuring in the 
1191     * Attributes of a certain custom relation. If no ModelElement of 
1192     * given name is found or the ModelElement has no <<RelDef>> stereotype
1193     * an empty list is returned
1194     *
1195     * @param roleName the name of the relation
1196     * @return List of optionlist names
1197     **
1198 
1199     public List getOptionListAttributesRelation(String roleName){
1200        ArrayList result = new ArrayList();
1201        boolean checked = false;
1202        String stereotype;
1203        Object o = getModelElement(roleName);
1204        if(o == null || o instanceof ModelElement == false)return result;
1205        ModelElement relation = (ModelElement)o;
1206        //now check of ModelObject is relation
1207        for ( Iterator i = getStereotypeNames(relation).iterator() ; i.hasNext() ; ){
1208           stereotype = (String)i.next();
1209           //System.out.println("stereotype found: "+stereotype);
1210           if(MMBaseUMLProfile.STEREOTYPE_CLASS_RELATION.equals(stereotype)){
1211               checked = true;
1212           }
1213        }
1214        if (!checked)return result;
1215        //now iterate over the attributes and find those goddamn optionlists
1216        //we are only gonna check the public fields, as those are the only ones
1217        //showing up in the wizard lists.
1218        String optionListName;
1219        if(relation instanceof Classifier){
1220           Collection c = getAllAttributes(relation, "true", "false", "true", "public");
1221           for ( Iterator i = c.iterator() ; i.hasNext() ; ){
1222              optionListName = ((MMBaseAttributeVo)i.next()).getOptionListDefinition();
1223              if (optionListName != null && !"".equals(optionListName)){
1224                 result.add(optionListName);
1225              }
1226           }
1227        }
1228        return result;
1229     }
1230   */  
1231     /***
1232     * Funcrion to obtain the varsion for a  builder class. If a tagged value
1233     * 'version' has been set on the class, and the value is a valid number,
1234     * this will be returned, otherwise it will return 0;
1235     *
1236     * @param object is a ModelElement that will be tested for the tagged value
1237     * @return String containing number
1238     **/
1239     public String getVersion(Object object){
1240        String result = null;
1241        if( object instanceof ModelElement == true){
1242          result = findTagValue((ModelElement)object, MMBaseUMLProfile.TAGGED_VALUE_CLASS_VERSION);
1243          if( result != null){
1244             try{
1245                Integer i = new Integer(result);
1246             }catch (NumberFormatException e){
1247                result = null;
1248             }
1249          }
1250        }
1251        return (result == null ? "0" : result); 
1252     }
1253     
1254    /***
1255     * Function to determin if relation is a specialization of posrel 
1256     *
1257     * @param relationName the name of a relation type
1258     * @return String containing 'true' if given relation is posrel 
1259     * specialization, otherwise 'false' 
1260     */   
1261    public String getIsPosrelSpecialization(String relationName){
1262       if( relationName.equals("posrel") )return "false";
1263       Object relation = getModelElement(relationName);
1264       if (relation != null){
1265          Collection c = getAllGeneralizations(relation,5);
1266          for (Iterator i = c.iterator() ; i.hasNext() ; ){
1267             Object o=i.next();
1268             if(o instanceof ModelElement == true){
1269                if (((ModelElement)o).getName().equals("posrel"))return "true";
1270             }
1271          }
1272       }
1273       return "false";
1274    }    
1275 }