001package org.andromda.cartridges.hibernate.metafacades;
002
003import java.text.MessageFormat;
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.List;
007import org.andromda.cartridges.hibernate.HibernateProfile;
008import org.andromda.cartridges.hibernate.HibernateUtils;
009import org.andromda.metafacades.uml.AssociationEndFacade;
010import org.andromda.metafacades.uml.Entity;
011import org.andromda.metafacades.uml.EntityAttribute;
012import org.andromda.metafacades.uml.EntityMetafacadeUtils;
013import org.andromda.metafacades.uml.GeneralizableElementFacade;
014import org.andromda.metafacades.uml.ModelElementFacade;
015import org.andromda.metafacades.uml.OperationFacade;
016import org.andromda.metafacades.uml.UMLMetafacadeProperties;
017import org.apache.commons.lang.ObjectUtils;
018import org.apache.commons.lang.StringUtils;
019
020/**
021 * <p> Provides support for the hibernate inheritance strategies of class
022 * (table per hierarchy), subclass (table per subclass in hierarchy) and
023 * concrete (table per class). With concrete the strategy can be changed lower
024 * down. Also provides for the root class being defined as an interface and the
025 * attributes remapped to the subclasses. This is useful in the concrete case
026 * because it has limitations in the associations.
027 * </p>
028 * <p> Also provides support for not generating the entity factory which is
029 * useful when using subclass mode.
030 * </p>
031 *
032 * @author Chad Brandon
033 * @author Martin West
034 * @author Carlos Cuenca
035 * @author Peter Friese
036 * @author Wouter Zoons
037 * @author Bob Fields
038 */
039public class HibernateEntityLogicImpl
040    extends HibernateEntityLogic
041{
042    private static final long serialVersionUID = 34L;
043    /**
044     * @param metaObject
045     * @param context
046     */
047    public HibernateEntityLogicImpl(
048        Object metaObject,
049        String context)
050    {
051        super(metaObject, context);
052    }
053
054    /**
055     * Value for one table per root class
056     */
057    private static final String INHERITANCE_STRATEGY_CLASS = "class";
058
059    /**
060     * Value for joined-subclass
061     */
062    private static final String INHERITANCE_STRATEGY_SUBCLASS = "subclass";
063
064    /**
065     * Value for one table per concrete class
066     */
067    private static final String INHERITANCE_STRATEGY_CONCRETE = "concrete";
068
069    /**
070     * Value make entity an interface, delegate attributes to subclasses.
071     */
072    private static final String INHERITANCE_STRATEGY_INTERFACE = "interface";
073
074    /**
075     * Value for one table per concrete class, (with union-subclass)
076     */
077    private static final String INHERITANCE_STRATEGY_UNION_SUBCLASS = "union-subclass";
078
079    /**
080     * Stores the valid inheritance strategies.
081     */
082    private static final Collection<String> inheritanceStrategies = new ArrayList<String>();
083
084    static
085    {
086        inheritanceStrategies.add(INHERITANCE_STRATEGY_CLASS);
087        inheritanceStrategies.add(INHERITANCE_STRATEGY_SUBCLASS);
088        inheritanceStrategies.add(INHERITANCE_STRATEGY_CONCRETE);
089        inheritanceStrategies.add(INHERITANCE_STRATEGY_INTERFACE);
090        inheritanceStrategies.add(INHERITANCE_STRATEGY_UNION_SUBCLASS);
091    }
092
093    /**
094     * Stores the default hibernate inheritance strategy.
095     */
096    private static final String INHERITANCE_STRATEGY = "hibernateInheritanceStrategy";
097
098    /**
099     * Stores the hibernate entity cache value.
100     */
101    private static final String HIBERNATE_ENTITY_CACHE = "hibernateEntityCache";
102
103    /**
104     * The namespace property storing the hibernate default-cascade value for an
105     * entity.
106     */
107    private static final String HIBERNATE_DEFAULT_CASCADE = "hibernateDefaultCascade";
108
109    /**
110     * Namespace property storing the default hibernate generator class.
111     */
112    private static final String DEFAULT_HIBERNATE_GENERATOR_CLASS = "defaultHibernateGeneratorClass";
113
114    /**
115     * Represents a <em>foreign</em> Hibernate generator class.
116     */
117    private static final String HIBERNATE_GENERATOR_CLASS_FOREIGN = "foreign";
118
119    /**
120     * Represents an <em>assigned</em> Hibernate generator class.
121     */
122    private static final String HIBERNATE_GENERATOR_CLASS_ASSIGNED = "assigned";
123    private static final String HIBERNATE_GENERATOR_CLASS_SEQUENCE = "sequence";
124
125    /**
126     * The namespace property for specifying a hibernate proxy for this entity.
127     */
128    private static final String HIBERNATE_PROXY = "hibernateProxy";
129
130    /**
131     * The "class" mapping name.
132     */
133    private static final String CLASS_MAPPING_NAME = "class";
134
135    /**
136     * The "joined-subclass" mapping name.
137     */
138    private static final String JOINED_SUBCLASS_MAPPING_NAME = "joined-subclass";
139
140    /**
141     * The "subclass" mapping name.
142     */
143    private static final String SUBCLASS_MAPPING_NAME = "subclass";
144
145    /**
146     * The "union-subclass" mapping name.
147     */
148    private static final String UNION_SUBCLASS_MAPPING_NAME = "union-subclass";
149
150    /**
151     * Return all the business operations (ones that are inherited as well as
152     * directly on the entity).
153     *
154     * @return all business operations
155     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getAllBusinessOperations()
156     */
157    protected Collection<OperationFacade> handleGetAllBusinessOperations()
158    {
159        Collection<OperationFacade> result = this.getBusinessOperations();
160        GeneralizableElementFacade general = this.getGeneralization();
161        // Allow for Entities that inherit from a non-Entity ancestor
162        if (general != null && general instanceof Entity)
163        {
164            Entity superElement = (Entity)general;
165            result.addAll(superElement.getBusinessOperations());
166            general = this.getGeneralization();
167        }
168
169        return result;
170    }
171
172    /**
173     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateInheritanceStrategy()
174     */
175    @Override
176    protected String handleGetHibernateInheritanceStrategy()
177    {
178        String inheritance = HibernateEntityLogicImpl.getInheritance(this);
179
180        for (HibernateEntity superEntity = this.getSuperEntity();
181            (superEntity != null) && StringUtils.isBlank(inheritance);)
182        {
183            inheritance = superEntity.getHibernateInheritanceStrategy();
184        }
185
186        inheritance = inheritance != null ? inheritance.toLowerCase() : null;
187
188        if (StringUtils.isBlank(inheritance) || !inheritanceStrategies.contains(inheritance))
189        {
190            inheritance = this.getDefaultInheritanceStrategy();
191        }
192
193        return inheritance;
194    }
195
196    /**
197     * Gets the default hibernate inheritance strategy.
198     *
199     * @return the default hibernate inheritance strategy.
200     */
201    private String getDefaultInheritanceStrategy()
202    {
203        return String.valueOf(this.getConfiguredProperty(INHERITANCE_STRATEGY));
204    }
205
206    /**
207     * Return the inheritance tagged value for for given <code>entity</code>.
208     *
209     * @param entity the HibernateEntity from which to retrieve the inheritance tagged
210     *        value.
211     * @return String inheritance tagged value.
212     */
213    private static String getInheritance(HibernateEntity entity)
214    {
215        String inheritance = null;
216
217        if (entity != null)
218        {
219            final Object value = entity.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_INHERITANCE);
220            if (value != null)
221            {
222                inheritance = String.valueOf(value);
223            }
224        }
225        return inheritance;
226    }
227
228    /**
229     * @see org.andromda.metafacades.uml.ClassifierFacade#getProperties()
230     */
231    public List<ModelElementFacade> getProperties()
232    {
233        List<ModelElementFacade> properties = new ArrayList<ModelElementFacade>();
234        properties.addAll(this.getAttributes());
235        for (final AssociationEndFacade end : this.getAssociationEnds())
236        {
237            final AssociationEndFacade otherEnd = end.getOtherEnd();
238            if (otherEnd.isNavigable() ||
239                (end.isChild() && isForeignHibernateGeneratorClass()))
240            {
241                properties.add(otherEnd);
242            }
243        }
244        return properties;
245    }
246
247    /**
248     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateInheritanceClass()
249     */
250    @Override
251    protected boolean handleIsHibernateInheritanceClass()
252    {
253        return this.getHibernateInheritanceStrategy().equalsIgnoreCase(INHERITANCE_STRATEGY_CLASS);
254    }
255
256    /**
257     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateInheritanceInterface()
258     */
259    @Override
260    protected boolean handleIsHibernateInheritanceInterface()
261    {
262        return this.getHibernateInheritanceStrategy().equalsIgnoreCase(INHERITANCE_STRATEGY_INTERFACE);
263    }
264
265    /**
266     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateInheritanceSubclass()
267     */
268    @Override
269    protected boolean handleIsHibernateInheritanceSubclass()
270    {
271        return this.getHibernateInheritanceStrategy().equalsIgnoreCase(INHERITANCE_STRATEGY_SUBCLASS);
272    }
273
274    /**
275     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateInheritanceConcrete()
276     */
277    @Override
278    protected boolean handleIsHibernateInheritanceConcrete()
279    {
280        return this.getHibernateInheritanceStrategy().equalsIgnoreCase(INHERITANCE_STRATEGY_CONCRETE);
281    }
282
283    /**
284     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateInheritanceUnionSubClass()
285     */
286    @Override
287    protected boolean handleIsHibernateInheritanceUnionSubClass()
288    {
289        String version = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_VERSION);
290        return (version.startsWith(HibernateGlobals.HIBERNATE_VERSION_3) || version.startsWith(HibernateGlobals.HIBERNATE_VERSION_4))
291            && this.getHibernateInheritanceStrategy().equalsIgnoreCase(INHERITANCE_STRATEGY_UNION_SUBCLASS);
292    }
293
294    /**
295     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isLazy()
296     */
297    @Override
298    protected boolean handleIsLazy()
299    {
300        String value = (String)findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_LAZY);
301        if (StringUtils.isBlank(value))
302        {
303            String version = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_VERSION);
304            value = version.startsWith(HibernateGlobals.HIBERNATE_VERSION_2) ? "false" : "true";
305        }
306        return Boolean.valueOf(value).booleanValue();
307    }
308
309    /**
310     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateCacheType()
311     */
312    @Override
313    protected String handleGetHibernateCacheType()
314    {
315        String cacheType = (String)findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_ENTITY_CACHE);
316        if (StringUtils.isBlank(cacheType))
317        {
318            cacheType = String.valueOf(this.getConfiguredProperty(HIBERNATE_ENTITY_CACHE));
319        }
320        return cacheType;
321    }
322
323    /**
324     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getFullyQualifiedEntityName()
325     */
326    @Override
327    protected String handleGetFullyQualifiedEntityName()
328    {
329        return HibernateMetafacadeUtils.getFullyQualifiedName(
330            this.getPackageName(),
331            this.getEntityName(),
332            null);
333    }
334
335    /**
336     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getFullyQualifiedEntityImplementationName()
337     */
338    @Override
339    protected String handleGetFullyQualifiedEntityImplementationName()
340    {
341        return HibernateMetafacadeUtils.getFullyQualifiedName(
342            this.getPackageName(),
343            this.getEntityImplementationName(),
344            null);
345    }
346
347    /**
348     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateDefaultCascade()
349     */
350    @Override
351    protected String handleGetHibernateDefaultCascade()
352    {
353        return StringUtils.trimToEmpty(String.valueOf(this.getConfiguredProperty(HIBERNATE_DEFAULT_CASCADE)));
354    }
355
356    /**
357     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateGeneratorClass()
358     */
359    @Override
360    protected String handleGetHibernateGeneratorClass()
361    {
362        String hibernateGeneratorClass;
363
364        // if the entity is using a foreign identifier, then
365        // we automatically set the identifier generator
366        // class to be foreign
367        if (this.isUsingForeignIdentifier())
368        {
369            hibernateGeneratorClass = HIBERNATE_GENERATOR_CLASS_FOREIGN;
370        }
371        else if (this.isUsingAssignedIdentifier())
372        {
373            hibernateGeneratorClass = HIBERNATE_GENERATOR_CLASS_ASSIGNED;
374        }
375        else
376        {
377            hibernateGeneratorClass =
378                (String)this.findTaggedValue(
379                    HibernateProfile.TAGGEDVALUE_HIBERNATE_GENERATOR_CLASS,
380                    false);
381
382            if (StringUtils.isBlank(hibernateGeneratorClass))
383            {
384                hibernateGeneratorClass = (String)this.getConfiguredProperty(DEFAULT_HIBERNATE_GENERATOR_CLASS);
385            }
386        }
387        return StringUtils.trimToEmpty(hibernateGeneratorClass);
388    }
389
390    /**
391     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isForeignHibernateGeneratorClass()
392     */
393    @Override
394    protected boolean handleIsForeignHibernateGeneratorClass()
395    {
396        // check to see if the entity is using a foreign identifier
397        // OR if the actual hibernate generator class is set to foreign
398        return this.isUsingForeignIdentifier() ||
399        this.getHibernateGeneratorClass().equalsIgnoreCase(HIBERNATE_GENERATOR_CLASS_FOREIGN);
400    }
401
402    /**
403     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isSequenceHibernateGeneratorClass()
404     */
405    @Override
406    protected boolean handleIsSequenceHibernateGeneratorClass()
407    {
408        return this.getHibernateGeneratorClass().equalsIgnoreCase(HIBERNATE_GENERATOR_CLASS_SEQUENCE);
409    }
410
411    /**
412     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getEntityName()
413     */
414    @Override
415    protected String handleGetEntityName()
416    {
417        String entityNamePattern = (String)this.getConfiguredProperty(HibernateGlobals.ENTITY_NAME_PATTERN);
418
419        return MessageFormat.format(
420            entityNamePattern,
421                StringUtils.trimToEmpty(this.getName()));
422    }
423
424    /**
425     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getEntityImplementationName()
426     */
427    @Override
428    protected String handleGetEntityImplementationName()
429    {
430        String implNamePattern =
431            String.valueOf(this.getConfiguredProperty(HibernateGlobals.ENTITY_IMPLEMENTATION_NAME_PATTERN));
432
433        return MessageFormat.format(
434            implNamePattern,
435                StringUtils.trimToEmpty(this.getName()));
436    }
437
438    /**
439     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateDiscriminatorColumn()
440     */
441    @Override
442    protected String handleGetHibernateDiscriminatorColumn()
443    {
444        String column = (String)findTaggedValue(HibernateProfile.TAGGEDVALUE_ENTITY_DISCRIMINATOR_COLUMN);
445
446        if (StringUtils.isBlank(column))
447        {
448            column = String.valueOf(this.getConfiguredProperty(HibernateGlobals.ENTITY_DISCRIMINATOR_COLUMN));
449        }
450
451        return column;
452    }
453
454    /**
455     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateDiscriminatorType()
456     */
457    @Override
458    protected String handleGetHibernateDiscriminatorType()
459    {
460        String type = (String)findTaggedValue(HibernateProfile.TAGGEDVALUE_ENTITY_DISCRIMINATOR_TYPE);
461
462        if (StringUtils.isBlank(type))
463        {
464            type = String.valueOf(this.getConfiguredProperty(HibernateGlobals.ENTITY_DISCRIMINATOR_TYPE));
465        }
466
467        return type;
468    }
469
470    /**
471     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateDiscriminatorLength()
472     */
473    @Override
474    protected int handleGetHibernateDiscriminatorLength()
475    {
476        return 1;
477    }
478
479    /**
480     * Override so that we retrieve only the operations that are classifier
481     * scope (i.e. static).
482     *
483     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntityLogic#getBusinessOperations()
484     */
485    @Override
486    public Collection<OperationFacade> getBusinessOperations()
487    {
488        return HibernateMetafacadeUtils.filterBusinessOperations(super.getBusinessOperations());
489    }
490
491    /**
492     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isBusinessOperationsPresent()
493     */
494    @Override
495    protected boolean handleIsBusinessOperationsPresent()
496    {
497        final Collection<OperationFacade> allBusinessOperations = this.getAllBusinessOperations();
498
499        return (allBusinessOperations != null) && !allBusinessOperations.isEmpty();
500    }
501
502    /**
503     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateProxy()
504     */
505    @Override
506    protected boolean handleIsHibernateProxy()
507    {
508        String hibernateProxy = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_PROXY);
509        if (StringUtils.isBlank(hibernateProxy))
510        {
511            hibernateProxy = (String)this.getConfiguredProperty(HIBERNATE_PROXY);
512        }
513        return Boolean.valueOf(hibernateProxy).booleanValue();
514    }
515
516    /**
517     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getEhCacheMaxElementsInMemory()
518     */
519    @Override
520    protected int handleGetEhCacheMaxElementsInMemory()
521    {
522        String maxElements = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_EHCACHE_MAX_ELEMENTS);
523        if (StringUtils.isBlank(maxElements))
524        {
525            maxElements = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_EHCACHE_MAX_ELEMENTS);
526        }
527        return Integer.parseInt(StringUtils.trimToEmpty(maxElements));
528    }
529
530    /**
531     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isEhCacheEternal()
532     */
533    @Override
534    protected boolean handleIsEhCacheEternal()
535    {
536        String eternal = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_EHCACHE_ETERNAL);
537        if (StringUtils.isBlank(eternal))
538        {
539            eternal = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_EHCACHE_ETERNAL);
540        }
541        return Boolean.valueOf(StringUtils.trimToEmpty(eternal)).booleanValue();
542    }
543
544    /**
545     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getEhCacheTimeToIdleSeconds()
546     */
547    @Override
548    protected int handleGetEhCacheTimeToIdleSeconds()
549    {
550        String timeToIdle =
551           (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_EHCACHE_TIME_TO_IDLE);
552        if (StringUtils.isBlank(timeToIdle))
553        {
554            timeToIdle = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_EHCACHE_TIME_TO_IDLE);
555        }
556        return Integer.parseInt(StringUtils.trimToEmpty(timeToIdle));
557    }
558
559    /**
560     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getEhCacheTimeToLiveSeconds()
561     */
562    @Override
563    protected int handleGetEhCacheTimeToLiveSeconds()
564    {
565        String timeToLive =
566           (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_EHCACHE_TIME_TO_LIVE);
567        if (StringUtils.isBlank(timeToLive))
568        {
569            timeToLive = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_EHCACHE_TIME_TO_LIVE);
570        }
571        return Integer.parseInt(StringUtils.trimToEmpty(timeToLive));
572    }
573
574    /**
575     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isEhCacheOverflowToDisk()
576     */
577    @Override
578    protected boolean handleIsEhCacheOverflowToDisk()
579    {
580        String eternal = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_EHCACHE_OVERFLOW_TO_DISK);
581        if (StringUtils.isBlank(eternal))
582        {
583            eternal = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_EHCACHE_OVERFLOW_TO_DISK);
584        }
585        return Boolean.valueOf(StringUtils.trimToEmpty(eternal)).booleanValue();
586    }
587
588    /**
589     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isHibernateCacheDistributed()
590     */
591    @Override
592    protected boolean handleIsHibernateCacheDistributed()
593    {
594        String distributed = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_ENTITYCACHE_DISTRIBUTED);
595        boolean distributedCachingEnabled = Boolean.valueOf(StringUtils.trimToEmpty(distributed)).booleanValue();
596
597        if (distributedCachingEnabled)
598        {
599            String entityCacheDistributed =
600                (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_ENTITYCACHE_DISTRIBUTED);
601            return Boolean.valueOf(StringUtils.trimToEmpty(entityCacheDistributed)).booleanValue();
602        }
603        return false;
604    }
605
606    /**
607     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isTableRequired()
608     */
609    @Override
610    protected boolean handleIsTableRequired()
611    {
612        return !this.isHibernateInheritanceClass() ||
613        (this.isHibernateInheritanceClass() && (this.getGeneralization() == null));
614    }
615
616    /**
617     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getMappingClassName()
618     */
619    @Override
620    protected String handleGetMappingClassName()
621    {
622        String mappingClassName = CLASS_MAPPING_NAME;
623        final HibernateEntity superEntity = this.getSuperEntity();
624
625        if ((superEntity != null) && !superEntity.isHibernateInheritanceInterface() &&
626            !superEntity.isHibernateInheritanceConcrete())
627        {
628            mappingClassName = JOINED_SUBCLASS_MAPPING_NAME;
629
630            if (this.isHibernateInheritanceClass())
631            {
632                mappingClassName = SUBCLASS_MAPPING_NAME;
633            }
634            else if (this.isHibernateInheritanceUnionSubClass())
635            {
636                mappingClassName = UNION_SUBCLASS_MAPPING_NAME;
637            }
638        }
639
640        return mappingClassName;
641    }
642
643    /**
644     * Gets the super entity for this entity (if one exists). If a
645     * generalization does not exist OR if it's not an instance of
646     * HibernateEntity then return null.
647     *
648     * @return the super entity or null if one doesn't exist.
649     */
650    private HibernateEntity getSuperEntity()
651    {
652        HibernateEntity superEntity = null;
653
654        if ((this.getGeneralization() != null) && this.getGeneralization() instanceof HibernateEntity)
655        {
656            superEntity = (HibernateEntity)this.getGeneralization();
657        }
658
659        return superEntity;
660    }
661
662    /**
663     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getSubclassKeyColumn()
664     */
665    @Override
666    protected String handleGetSubclassKeyColumn()
667    {
668        String column = null;
669        final HibernateEntity superEntity = this.getSuperEntity();
670
671        if ((superEntity != null) && superEntity.isHibernateInheritanceSubclass())
672        {
673            ModelElementFacade facade = this.getIdentifiers().iterator().next();
674            if (facade instanceof EntityAttribute)
675            {
676                column = ((EntityAttribute)facade).getColumnName();
677            }
678        }
679
680        return column;
681    }
682
683    /**
684     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isRequiresMapping()
685     */
686    @Override
687    protected boolean handleIsRequiresMapping()
688    {
689        final HibernateEntity superEntity = this.getSuperEntity();
690        return HibernateUtils.mapSubclassesInSeparateFile(
691            (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_MAPPING_STRATEGY)) ||
692            this.isRoot() &&
693            (
694                !this.isHibernateInheritanceInterface() || this.getSpecializations().isEmpty() ||
695                (superEntity != null && superEntity.isHibernateInheritanceInterface())
696            );
697    }
698
699    /**
700     * Indicates if this entity is a <code>root</code> entity (meaning it
701     * doesn't specialize anything).
702     */
703    private boolean isRoot()
704    {
705        final HibernateEntity superEntity = this.getSuperEntity();
706        boolean abstractConcreteEntity =
707            (this.isHibernateInheritanceConcrete() || this.isHibernateInheritanceInterface()) && this.isAbstract();
708
709        return (
710            this.getSuperEntity() == null ||
711            (superEntity.isHibernateInheritanceInterface() || superEntity.isHibernateInheritanceConcrete())
712        ) && !abstractConcreteEntity;
713    }
714
715    /**
716     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isRequiresSpecializationMapping()
717     */
718    @Override
719    protected boolean handleIsRequiresSpecializationMapping()
720    {
721        return !HibernateUtils.mapSubclassesInSeparateFile(
722            (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_MAPPING_STRATEGY)) && this.isRoot() &&
723        (
724            this.isHibernateInheritanceSubclass() || this.isHibernateInheritanceClass() ||
725            this.isHibernateInheritanceUnionSubClass()
726        );
727    }
728
729    /**
730     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isDynamicInsert()
731     */
732    @Override
733    protected boolean handleIsDynamicInsert()
734    {
735        String dynamicInsert =
736            (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_ENTITY_DYNAMIC_INSERT);
737        if (StringUtils.isBlank(dynamicInsert))
738        {
739            dynamicInsert = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_ENTITY_DYNAMIC_INSERT);
740        }
741        return Boolean.valueOf(dynamicInsert).booleanValue();
742    }
743
744    /**
745     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isDynamicUpdate()
746     */
747    @Override
748    protected boolean handleIsDynamicUpdate()
749    {
750        String dynamicUpdate =
751            (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_ENTITY_DYNAMIC_UPDATE);
752        if (StringUtils.isBlank(dynamicUpdate))
753        {
754            dynamicUpdate = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_ENTITY_DYNAMIC_UPDATE);
755        }
756        return Boolean.valueOf(dynamicUpdate).booleanValue();
757    }
758
759    /**
760     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#isMappingRequiresSuperProperties()
761     */
762    @Override
763    protected boolean handleIsMappingRequiresSuperProperties()
764    {
765        return this.isHibernateInheritanceInterface() || (this.isHibernateInheritanceConcrete() && this.isAbstract());
766    }
767
768    /**
769     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateVersionProperty()
770     */
771    @Override
772    protected String handleGetHibernateVersionProperty()
773    {
774        String version = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_VERSION_PROPERTY);
775        if (StringUtils.isBlank(version))
776        {
777            version = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_VERSION_PROPERTY);
778        }
779        return version;
780    }
781
782    /**
783     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateVersionPropertySqlName()
784     */
785    @Override
786    protected String handleGetHibernateVersionPropertySqlName()
787    {
788        return EntityMetafacadeUtils.toSqlName(this.getHibernateVersionProperty(), this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR));
789    }
790
791    /**
792     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getVersion()
793     */
794    @Override
795    protected int handleGetVersion()
796    {
797        String version = (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_VERSION);
798        if (version==null)
799        {
800            version = HibernateGlobals.HIBERNATE_VERSION_3;
801        }
802        else
803        {
804            version = version.substring(0, 1);
805        }
806        return Integer.parseInt(version);
807    }
808
809    private boolean isXmlPersistenceActive()
810    {
811        return HibernateUtils.isXmlPersistenceActive(
812            (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_VERSION),
813            (String)this.getConfiguredProperty(HibernateGlobals.HIBERNATE_XML_PERSISTENCE));
814    }
815
816    /**
817     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntityLogic#handleGetXmlTagName()
818     */
819    protected String handleGetXmlTagName()
820    {
821        String tagName = null;
822        if (isXmlPersistenceActive())
823        {
824            tagName = (String)this.findTaggedValue(HibernateProfile.TAGGEDVALUE_HIBERNATE_XML_TAG_NAME);
825
826            if (StringUtils.isBlank(tagName))
827            {
828                tagName = this.getName();
829            }
830        }
831        return (StringUtils.isBlank(tagName)) ? null : tagName;
832    }
833
834    /**
835     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getHibernateDiscriminatorValue()
836     */
837    @Override
838    protected String handleGetHibernateDiscriminatorValue()
839    {
840        String value = (String)findTaggedValue(HibernateProfile.TAGGEDVALUE_ENTITY_DISCRIMINATOR_VALUE);
841        if (StringUtils.isBlank(value))
842        {
843            value = getEntityImplementationName();
844        }
845        return value;
846    }
847
848    /**
849     * @see org.andromda.cartridges.hibernate.metafacades.HibernateEntity#getSequenceName()
850     */
851    @Override
852    protected String handleGetSequenceName()
853    {
854        String sequenceName = this.getTableName();
855        final String sequenceSuffix = this.getSequenceSuffix();
856        // Implicit conversion from short to int
857        final int maxLength = this.getMaxSqlNameLength() - this.getSequenceSuffix().length();
858        if (maxLength > 0)
859        {
860            final Object method = this.getConfiguredProperty(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD);
861            sequenceName = EntityMetafacadeUtils.ensureMaximumNameLength(sequenceName, Integer.valueOf(maxLength).shortValue(), (String)method) + sequenceSuffix;
862        }
863        return sequenceName;
864    }
865
866    private static final String SEQUENCE_IDENTIFIER_SUFFIX = "sequenceIdentifierSuffix";
867
868    private String getSequenceSuffix()
869    {
870        return ObjectUtils.toString(this.getConfiguredProperty(SEQUENCE_IDENTIFIER_SUFFIX));
871    }
872}