1 package org.andromda.metafacades.uml;
2
3 import java.text.CharacterIterator;
4 import java.text.StringCharacterIterator;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Random;
11 import org.andromda.core.common.ExceptionUtils;
12 import org.apache.commons.lang.StringEscapeUtils;
13 import org.apache.commons.lang.StringUtils;
14 import org.apache.log4j.Logger;
15
16
17
18
19
20
21
22 public class EntityMetafacadeUtils
23 {
24
25
26
27 private static final Logger LOGGER = Logger.getLogger(EntityMetafacadeUtils.class);
28
29
30
31
32
33
34
35
36
37
38
39 public static String toSqlName(
40 String modelElementName,
41 Object separator)
42 {
43 ExceptionUtils.checkEmpty(
44 "modelElementName",
45 modelElementName);
46
47 StringBuilder sqlName = new StringBuilder();
48 StringCharacterIterator iterator = new StringCharacterIterator(StringUtils.uncapitalize(modelElementName));
49
50 for (char character = iterator.first(); character != CharacterIterator.DONE; character = iterator.next())
51 {
52 if (Character.isUpperCase(character))
53 {
54 sqlName.append(separator);
55 }
56 character = Character.toUpperCase(character);
57 sqlName.append(character);
58 }
59 return StringEscapeUtils.escapeSql(sqlName.toString());
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public static String getSqlNameFromTaggedValue(
78 String prefix,
79 ModelElementFacade element,
80 String name,
81 Short nameMaxLength,
82 Object separator,
83 Object shortenSqlNamesMethod)
84 {
85 return getSqlNameFromTaggedValue(
86 prefix,
87 element,
88 name,
89 nameMaxLength,
90 null,
91 separator,
92 shortenSqlNamesMethod);
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public static String getSqlNameFromTaggedValue(
111 ModelElementFacade element,
112 String name,
113 Short nameMaxLength,
114 String suffix,
115 Object separator,
116 Object shortenSqlNamesMethod)
117 {
118 return getSqlNameFromTaggedValue(
119 null,
120 element,
121 name,
122 nameMaxLength,
123 suffix,
124 separator,
125 shortenSqlNamesMethod);
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public static String getSqlNameFromTaggedValue(
142 ModelElementFacade element,
143 String name,
144 Short nameMaxLength,
145 Object separator,
146 Object shortenSqlNamesMethod)
147 {
148 return getSqlNameFromTaggedValue(
149 null,
150 element,
151 name,
152 nameMaxLength,
153 null,
154 separator,
155 shortenSqlNamesMethod);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 public static String getSqlNameFromTaggedValue(
176 String prefix,
177 final ModelElementFacade element,
178 String name,
179 final Short nameMaxLength,
180 String suffix,
181 final Object separator,
182 final Object shortenSqlNamesMethod)
183 {
184 if (element != null)
185 {
186 Object value = element.findTaggedValue(name);
187 StringBuilder buffer = new StringBuilder(StringUtils.trimToEmpty((String)value));
188 if (StringUtils.isEmpty(buffer.toString()))
189 {
190
191
192 buffer = new StringBuilder(toSqlName(
193 element.getName(),
194 separator));
195 suffix = StringUtils.trimToEmpty(suffix);
196 prefix = StringUtils.trimToEmpty(prefix);
197 if (nameMaxLength != null)
198 {
199 final short maxLength = (short)(nameMaxLength.shortValue() - suffix.length() - prefix.length());
200 buffer =
201 new StringBuilder(
202 EntityMetafacadeUtils.ensureMaximumNameLength(
203 buffer.toString(),
204 Short.valueOf(maxLength),
205 (String)shortenSqlNamesMethod));
206 }
207 if (StringUtils.isNotBlank(prefix))
208 {
209 buffer.insert(
210 0,
211 prefix);
212 }
213 if (StringUtils.isNotBlank(suffix))
214 {
215 buffer.append(suffix);
216 }
217 }
218 name = buffer.toString();
219 }
220 return name;
221 }
222
223 private static List<Entity> sortedEntities;
224
225
226
227
228
229
230
231
232
233 public static List<Entity> sortEntities(
234 final Collection<Entity> entities,
235 boolean ascending)
236 {
237
238
239 List<Entity> sorted = new ArrayList<Entity>();
240 if (sortedEntities==null)
241 {
242 sortedEntities = new ArrayList<Entity>();
243 }
244 if (entities == null || entities.isEmpty() ||
245 (sortedEntities!=null && !sortedEntities.isEmpty() && sortedEntities.size() == entities.size()
246 && sortedEntities.contains(entities.iterator().next())))
247 {
248 sorted = sortedEntities;
249 }
250 else
251 {
252
253 sortedEntities.clear();
254
255 List<Entity> toBeMoved = new ArrayList<Entity>();
256 List<Entity> unsorted = new ArrayList<Entity>();
257 for (Entity entity : entities)
258 {
259
260 if (entity.isAbstract())
261 {
262 toBeMoved.add(entity);
263 }
264 else
265 {
266
267
268
269 if (entity.getNavigableConnectingEnds().size()==0)
270 {
271 sorted.add(entity);
272
273 }
274 else
275 {
276 unsorted.add(entity);
277 }
278 }
279 }
280
281 for (Entity entity : toBeMoved)
282 {
283 entities.remove(entity);
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313 int moveCount = 1;
314 while (unsorted.size() > 0 && moveCount > 0)
315 {
316 toBeMoved = new ArrayList<Entity>();
317 for (Entity entity : unsorted)
318 {
319 Collection<AssociationEndFacade> ends = entity.getNavigableConnectingEnds();
320
321 boolean createFirst = true;
322 for (AssociationEndFacade end : ends)
323 {
324 ClassifierFacade entityEnd = end.getType();
325
326 int referencedPosition = unsorted.lastIndexOf(entityEnd);
327
328 if (referencedPosition > -1 && UMLMetafacadeUtils.isOwningEnd(end) && !entityEnd.getFullyQualifiedName().equals(entity.getFullyQualifiedName()))
329 {
330
331 createFirst = false;
332 break;
333 }
334 }
335 if (createFirst)
336 {
337 toBeMoved.add(entity);
338
339 }
340 }
341 moveCount = toBeMoved.size();
342
343
344
345
346
347
348 for (Entity entity : toBeMoved)
349 {
350 unsorted.remove(entity);
351 sorted.add(entity);
352 }
353 }
354 if (moveCount==0 && unsorted.size() > 0)
355 {
356
357 String circular = "Circular relationships between Entities:";
358 for (Entity entity : unsorted)
359 {
360 circular += " " + entity.getName();
361 }
362 LOGGER.error(circular);
363
364 }
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 sorted.addAll(unsorted);
416 sortedEntities = sorted;
417 }
418 if (!ascending)
419 {
420 Collections.reverse(sorted);
421 }
422 return sorted;
423 }
424
425
426
427
428
429
430
431
432 public static int getPriority(
433 final Entity entity)
434 {
435 int priority = 0;
436 if (sortedEntities!=null && !sortedEntities.isEmpty())
437 {
438 priority = sortedEntities.indexOf(entity);
439 if (priority < 1)
440 {
441 priority = 0;
442 }
443 else
444 {
445
446 priority = priority*10 + 10;
447 }
448 }
449 return priority;
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463 public static String ensureMaximumNameLength(
464 String name,
465 Short nameMaxLength,
466 String method)
467 {
468 if (StringUtils.isNotBlank(name) && nameMaxLength != null)
469 {
470 short max = nameMaxLength.shortValue();
471 if(method != null && method.equalsIgnoreCase(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD_REMOVE_VOWELS))
472 {
473 while(name.length() > max)
474 {
475 final String[] vowels = new String[]{"A","E","I","O","U","a","e","i","o","u"};
476 final int lastVowelPos = StringUtils.lastIndexOfAny(name, vowels);
477 if(lastVowelPos == -1)
478 {
479 break;
480 }
481 else
482 {
483 name = name.substring(0,lastVowelPos)+name.substring(lastVowelPos+1);
484 }
485 }
486 }
487
488 if (name.length() > max)
489 {
490 name = name.substring(
491 0,
492 max);
493 }
494 }
495 return name;
496 }
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511 public static Collection<ModelElementFacade> getIdentifiers(
512 final Entity entity,
513 final boolean follow)
514 {
515
516 final Collection<ModelElementFacade> identifiers = new ArrayList<ModelElementFacade>();
517
518 final Collection<AttributeFacade> attributes = new ArrayList<AttributeFacade>(entity.getAttributes());
519 MetafacadeUtils.filterByStereotype(
520 attributes,
521 UMLProfile.STEREOTYPE_IDENTIFIER);
522 identifiers.addAll(attributes);
523 final Collection<AssociationEndFacade> associations = new ArrayList<AssociationEndFacade>(entity.getNavigableConnectingEnds(follow));
524 MetafacadeUtils.filterByStereotype(
525 associations,
526 UMLProfile.STEREOTYPE_IDENTIFIER);
527 identifiers.addAll(associations);
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 final Collection<ModelElementFacade> sortedIdentifiers = new ArrayList<ModelElementFacade>();
543 String joinOrder = (String)entity.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_JOINCOLUMN_ORDER);
544 if (StringUtils.isNotBlank(joinOrder))
545 {
546
547 String[] joinList = StringUtils.split(joinOrder, " ,;|");
548 for (String column : joinList)
549 {
550 for (ModelElementFacade facade : identifiers)
551 {
552 if (facade instanceof EntityAssociationEnd)
553 {
554 EntityAssociationEnd assoc = (EntityAssociationEnd)facade;
555 if (assoc.getColumnName().equalsIgnoreCase(column))
556 {
557 sortedIdentifiers.add(assoc);
558
559 }
560 }
561 else if (facade instanceof EntityAttribute)
562 {
563 EntityAttribute attr = (EntityAttribute)facade;
564 if (attr.getColumnName().equalsIgnoreCase(column))
565 {
566 sortedIdentifiers.add(attr);
567
568 }
569 }
570 }
571 }
572
573
574
575 for (ModelElementFacade facade : identifiers)
576 {
577 boolean contains = false;
578 for (ModelElementFacade sorted : sortedIdentifiers)
579 {
580 if (sorted.getFullyQualifiedName().equals(facade.getFullyQualifiedName()))
581 {
582 contains = true;
583
584 }
585 }
586 if (!contains)
587 {
588 sortedIdentifiers.add(facade);
589
590 }
591 }
592
593 }
594 else
595 {
596 sortedIdentifiers.addAll(identifiers);
597 }
598 if (sortedIdentifiers.isEmpty() && follow && entity.getGeneralization() instanceof Entity)
599 {
600 sortedIdentifiers.addAll(getIdentifiers((Entity)entity.getGeneralization(), follow));
601 }
602 return sortedIdentifiers;
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619 public static Collection<ModelElementFacade> getIdentifierAttributes(
620 final Entity entity,
621 final boolean follow)
622 {
623 Collection<ModelElementFacade> identifierAttributes = new ArrayList<ModelElementFacade>();
624 final Collection<ModelElementFacade> identifiers = EntityMetafacadeUtils.getIdentifiers(entity, follow);
625
626 for (ModelElementFacade identifier : identifiers)
627 {
628 if (identifier instanceof AssociationEndFacade)
629 {
630 AssociationEndFacade associationEnd = (AssociationEndFacade)identifier;
631 ClassifierFacade classifier = associationEnd.getType();
632 if (classifier instanceof Entity)
633 {
634 Collection<ModelElementFacade> entityIdentifiers = getIdentifierAttributes((Entity)classifier, true);
635 identifierAttributes.addAll(entityIdentifiers);
636 }
637 }
638 else
639 {
640 identifierAttributes.add(identifier);
641 }
642 }
643 if (identifiers.isEmpty() && follow && entity.getGeneralization() instanceof Entity)
644 {
645 identifierAttributes.addAll(getIdentifiers((Entity)entity.getGeneralization(), follow));
646 }
647
648 String joinOrder = (String)entity.findTaggedValue("andromda_persistence_joincolumn_order");
649
650
651
652
653
654
655
656
657 if (StringUtils.isNotBlank(joinOrder))
658 {
659 final Collection<ModelElementFacade> sortedIdentifiers = new ArrayList<ModelElementFacade>();
660 String[] joinList = StringUtils.split(joinOrder, " ,;|");
661 for (String column : joinList)
662 {
663 for (ModelElementFacade facade : identifierAttributes)
664 {
665 if (facade instanceof EntityAssociationEnd)
666 {
667 EntityAssociationEnd assoc = (EntityAssociationEnd)facade;
668 if (assoc.getColumnName().equalsIgnoreCase(column))
669 {
670 sortedIdentifiers.add(assoc);
671 }
672 }
673 else if (facade instanceof EntityAttribute)
674 {
675 EntityAttribute attr = (EntityAttribute)facade;
676 if (attr.getColumnName().equalsIgnoreCase(column))
677 {
678 sortedIdentifiers.add(attr);
679 }
680 }
681 }
682 }
683
684
685 if (sortedIdentifiers.size() < identifierAttributes.size())
686 for (ModelElementFacade facade : identifierAttributes)
687 {
688 if (!sortedIdentifiers.contains(facade))
689 {
690 sortedIdentifiers.add(facade);
691 }
692 }
693 identifierAttributes = sortedIdentifiers;
694 }
695 else
696 {
697 identifiers.addAll(identifierAttributes);
698 }
699 return identifierAttributes;
700 }
701
702
703
704
705
706
707
708
709
710
711 public static String constructSqlTypeName(
712 final String typeName,
713 final String columnLength)
714 {
715 String value = typeName;
716 if (StringUtils.isNotBlank(typeName))
717 {
718 final char beginChar = '(';
719 final char endChar = ')';
720 final int beginIndex = value.indexOf(beginChar);
721 final int endIndex = value.indexOf(endChar);
722 if (beginIndex != -1 && endIndex != -1 && endIndex > beginIndex)
723 {
724 String replacement = value.substring(
725 beginIndex,
726 endIndex) + endChar;
727 value = StringUtils.replace(
728 value,
729 replacement,
730 beginChar + columnLength + endChar);
731 }
732 else
733 {
734 value = value + beginChar + columnLength + endChar;
735 }
736 }
737 return value;
738 }
739
740
741
742
743
744
745
746
747
748
749
750
751 public static String getForeignKeyConstraintName(EntityAssociationEnd associationEnd, String suffix, String sqlNameSeparator, String maxLengthProperty, String shortenSqlNamesMethod)
752 {
753 String constraintName;
754
755 final Object taggedValueObject = associationEnd.findTaggedValue(
756 UMLProfile.TAGGEDVALUE_PERSISTENCE_FOREIGN_KEY_CONSTRAINT_NAME);
757 if (taggedValueObject == null)
758 {
759
760 StringBuilder buffer = new StringBuilder();
761
762 final ClassifierFacade type = associationEnd.getOtherEnd().getType();
763 if (type instanceof Entity)
764 {
765 Entity entity = (Entity)type;
766 buffer.append(entity.getTableName());
767 }
768 else
769 {
770
771 buffer.append(type.getName().toUpperCase());
772 }
773
774 buffer.append(sqlNameSeparator);
775 buffer.append(associationEnd.getColumnName());
776 constraintName = buffer.toString();
777
778
779 final short maxLength = (short)(Short.valueOf(maxLengthProperty).shortValue() - suffix.length());
780 buffer = new StringBuilder(EntityMetafacadeUtils.ensureMaximumNameLength(constraintName, Short.valueOf(maxLength), shortenSqlNamesMethod));
781 buffer.append(suffix);
782 constraintName = EntityMetafacadeUtils.getUniqueForeignKeyConstraintName(buffer.toString());
783 }
784 else
785 {
786
787 constraintName = taggedValueObject.toString();
788 }
789 return constraintName;
790 }
791
792
793
794
795
796
797 private static Collection<String> foreignKeyConstraintNameCache = new ArrayList<String>();
798
799
800
801
802
803
804
805
806 private static String getUniqueForeignKeyConstraintName(String proposedName)
807 {
808 final char[] characters = proposedName.toCharArray();
809 int numericValue = 0;
810 for (int ctr = 0; ctr < characters.length; ctr++)
811 {
812 numericValue = numericValue + Character.getNumericValue(characters[0]);
813 }
814 return getUniqueForeignKeyConstraintName(proposedName, new Random(numericValue));
815 }
816
817
818
819
820
821
822
823
824
825 private static String getUniqueForeignKeyConstraintName(String proposedName, final Random random)
826 {
827 String name;
828 if (foreignKeyConstraintNameCache.contains(proposedName))
829 {
830 final char[] characters = proposedName.toCharArray();
831 int randomInt = random.nextInt(characters.length);
832 char randomChar = Character.toUpperCase(characters[randomInt]);
833 proposedName = proposedName.substring(0, proposedName.length() - 1) + randomChar;
834 name = getUniqueForeignKeyConstraintName(proposedName, random);
835 }
836 else
837 {
838 name = proposedName;
839 foreignKeyConstraintNameCache.add(name);
840 }
841 return name;
842 }
843
844
845
846
847 public static void clearForeignKeyConstraintNameCache()
848 {
849 foreignKeyConstraintNameCache.clear();
850 }
851
852
853
854
855
856
857
858
859
860 public static PackageFacade getTopLevelPackage(LinkedHashSet<ClassifierFacade> classifiers, boolean entityOnly)
861 {
862 PackageFacade pkgFacade = null;
863 if (classifiers == null || classifiers.isEmpty()) return pkgFacade;
864
865 List<PackageFacade> packages = new ArrayList<PackageFacade>();
866 for (ClassifierFacade classifier : classifiers)
867 {
868
869 if (!classifier.isDataType())
870 {
871 if (!entityOnly || classifier instanceof Entity)
872 {
873 if (classifier.getStereotypeNames().size() > 0 && !packages.contains(classifier.getPackage()))
874 {
875 packages.add((PackageFacade)classifier.getPackage());
876
877 }
878 }
879 }
880 }
881 if (packages.size()>0)
882 {
883 pkgFacade = packages.get(0);
884
885 for (PackageFacade pkg : packages)
886 {
887
888 if (pkgFacade.getFullyQualifiedName().indexOf(pkg.getFullyQualifiedName()) > 0)
889 {
890 pkgFacade = pkg;
891 }
892 else if (pkg.getFullyQualifiedName().indexOf(pkgFacade.getFullyQualifiedName()) > 0)
893 {
894
895 }
896 else
897 {
898
899 }
900 }
901
902 }
903 return pkgFacade;
904 }
905 }