001package org.andromda.cartridges.spring.metafacades;
002
003import java.text.MessageFormat;
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.Iterator;
007import org.andromda.cartridges.spring.SpringHibernateUtils;
008import org.andromda.cartridges.spring.SpringProfile;
009import org.andromda.metafacades.uml.AttributeFacade;
010import org.andromda.metafacades.uml.ClassifierFacade;
011import org.andromda.metafacades.uml.DependencyFacade;
012import org.andromda.metafacades.uml.EntityQueryOperation;
013import org.andromda.metafacades.uml.EnumerationFacade;
014import org.andromda.metafacades.uml.FilteredCollection;
015import org.andromda.metafacades.uml.GeneralizableElementFacade;
016import org.andromda.metafacades.uml.OperationFacade;
017import org.andromda.metafacades.uml.ValueObject;
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020
021
022/**
023 * MetafacadeLogic implementation for org.andromda.cartridges.spring.metafacades.SpringEntity.
024 *
025 * @see org.andromda.cartridges.spring.metafacades.SpringEntity
026 */
027public class SpringEntityLogicImpl
028    extends SpringEntityLogic
029{
030    private static final long serialVersionUID = 34L;
031    /**
032     * Public constructor for SpringEntityLogicImpl
033     * @param metaObject
034     * @param context
035     * @see org.andromda.cartridges.spring.metafacades.SpringEntity
036     */
037    public SpringEntityLogicImpl(
038        Object metaObject,
039        String context)
040    {
041        super(metaObject, context);
042    }
043
044    /**
045     * Value for one Table per root class
046     */
047    private static final String INHERITANCE_STRATEGY_CLASS = "class";
048
049    /**
050     * Value for joined-subclass
051     */
052    private static final String INHERITANCE_STRATEGY_SUBCLASS = "subclass";
053
054    /**
055     * Value for one Table per concrete class
056     */
057    private static final String INHERITANCE_STRATEGY_CONCRETE = "concrete";
058
059    /**
060     * Value make Entity an interface, delegate attributes to subclasses.
061     */
062    private static final String INHERITANCE_STRATEGY_INTERFACE = "interface";
063
064    /**
065     * Stores the valid inheritance strategies.
066     */
067    private static final Collection<String> INHERITANCE_STRATEGIES = new ArrayList<String>();
068
069    static
070    {
071        INHERITANCE_STRATEGIES.add(INHERITANCE_STRATEGY_CLASS);
072        INHERITANCE_STRATEGIES.add(INHERITANCE_STRATEGY_SUBCLASS);
073        INHERITANCE_STRATEGIES.add(INHERITANCE_STRATEGY_CONCRETE);
074        INHERITANCE_STRATEGIES.add(INHERITANCE_STRATEGY_INTERFACE);
075    }
076
077    /**
078     * @return getDaoNamePattern().replaceAll("\\{0\\}", getName())
079     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getDaoName()
080     */
081    protected String handleGetDaoName()
082    {
083        return this.getDaoNamePattern().replaceAll(
084            "\\{0\\}",
085            this.getName());
086    }
087
088    /**
089     * Gets the value of the {@link SpringGlobals#DAO_PATTERN}
090     *
091     * @return the DAO name pattern.
092     */
093    private String getDaoNamePattern()
094    {
095        return String.valueOf(this.getConfiguredProperty(SpringGlobals.DAO_PATTERN));
096    }
097
098    /**
099     * @return fullyQualifiedName
100     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getFullyQualifiedDaoName()
101     */
102    protected String handleGetFullyQualifiedDaoName()
103    {
104        return SpringMetafacadeUtils.getFullyQualifiedName(
105            this.getPackageName(),
106            this.getDaoName());
107    }
108
109    /**
110     * @return daoImplementationName
111     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getDaoImplementationName()
112     */
113    protected String handleGetDaoImplementationName()
114    {
115        return this.getDaoImplementationNamePattern().replaceAll(
116            "\\{0\\}",
117            this.getName());
118    }
119
120    /**
121     * Gets the value of the {@link SpringGlobals#DAO_IMPLEMENTATION_PATTERN}
122     *
123     * @return the DAO implementation name pattern.
124     */
125    private String getDaoImplementationNamePattern()
126    {
127        return String.valueOf(this.getConfiguredProperty(SpringGlobals.DAO_IMPLEMENTATION_PATTERN));
128    }
129
130    /**
131     * @return fullyQualifiedDaoImplementationName
132     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getFullyQualifiedDaoImplementationName()
133     */
134    protected String handleGetFullyQualifiedDaoImplementationName()
135    {
136        return SpringMetafacadeUtils.getFullyQualifiedName(
137            this.getPackageName(),
138            this.getDaoImplementationName());
139    }
140
141    /**
142     * @return DaoBaseName
143     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getDaoBaseName()
144     */
145    protected String handleGetDaoBaseName()
146    {
147        return this.getDaoBaseNamePattern().replaceAll(
148            "\\{0\\}",
149            this.getName());
150    }
151
152    /**
153     * Gets the value of the {@link SpringGlobals#DAO_BASE_PATTERN}
154     *
155     * @return the DAO base name pattern.
156     */
157    private String getDaoBaseNamePattern()
158    {
159        return String.valueOf(this.getConfiguredProperty(SpringGlobals.DAO_BASE_PATTERN));
160    }
161
162    /**
163     * @return FullyQualifiedDaoBaseName
164     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getFullyQualifiedDaoBaseName()
165     */
166    protected String handleGetFullyQualifiedDaoBaseName()
167    {
168        return SpringMetafacadeUtils.getFullyQualifiedName(
169            this.getPackageName(),
170            this.getDaoBaseName());
171    }
172
173    /**
174     * @return EntityImplementationName
175     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getEntityImplementationName()
176     */
177    protected String handleGetEntityImplementationName()
178    {
179        return this.getEntityName() + SpringGlobals.IMPLEMENTATION_SUFFIX;
180    }
181
182    /**
183     * @return FullyQualifiedEntityImplementationName
184     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getFullyQualifiedEntityImplementationName()
185     */
186    protected String handleGetFullyQualifiedEntityImplementationName()
187    {
188        return SpringMetafacadeUtils.getFullyQualifiedName(
189            this.getPackageName(),
190            this.getEntityName(),
191            SpringGlobals.IMPLEMENTATION_SUFFIX);
192    }
193
194    /**
195     * @param targetSuffix
196     * @return BeanName
197     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getBeanName(boolean)
198     */
199    protected String handleGetBeanName(boolean targetSuffix)
200    {
201        final String beanName = StringUtils.uncapitalize(StringUtils.trimToEmpty(this.getName()));
202        StringBuilder beanNameBuffer = new StringBuilder(String.valueOf(this.getConfiguredProperty(SpringGlobals.BEAN_NAME_PREFIX)));
203        beanNameBuffer.append(this.getDaoNamePattern().replaceAll("\\{0\\}", beanName));
204        if (targetSuffix)
205        {
206            beanNameBuffer.append(SpringGlobals.BEAN_NAME_TARGET_SUFFIX);
207        }
208        return beanNameBuffer.toString();
209    }
210
211    /**
212     * @return EntityName
213     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getEntityName()
214     */
215    protected String handleGetEntityName()
216    {
217        final String entityNamePattern = (String)this.getConfiguredProperty("entityNamePattern");
218        return MessageFormat.format(
219            entityNamePattern,
220                StringUtils.trimToEmpty(this.getName()));
221    }
222
223    /**
224     * @return FullyQualifiedEntityName
225     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getFullyQualifiedEntityName()
226     */
227    protected String handleGetFullyQualifiedEntityName()
228    {
229        return SpringMetafacadeUtils.getFullyQualifiedName(
230            this.getPackageName(),
231            this.getEntityName(),
232            null);
233    }
234
235    /**
236     * @return Object Root
237     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getRoot()
238     */
239    protected Object handleGetRoot()
240    {
241        GeneralizableElementFacade generalization = this;
242        while(generalization.getGeneralization() != null && generalization instanceof SpringEntity)
243        {
244            generalization = generalization.getGeneralization();
245        }
246        return generalization;
247    }
248
249    /**
250     * @return IsDaoBusinessOperationsPresent
251     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isDaoBusinessOperationsPresent()
252     */
253    protected boolean handleIsDaoBusinessOperationsPresent()
254    {
255        return this.getDaoBusinessOperations() != null && !this.getDaoBusinessOperations().isEmpty();
256    }
257
258    /**
259     * @return DaoBusinessOperations
260     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getDaoBusinessOperations()
261     */
262    protected Collection<OperationFacade> handleGetDaoBusinessOperations()
263    {
264        // operations that are not finders and static
265        Collection<EntityQueryOperation> finders = this.getQueryOperations();
266        Collection<OperationFacade> operations = this.getOperations();
267
268        Collection<OperationFacade> nonFinders = CollectionUtils.subtract(operations, finders);
269        return new FilteredCollection(nonFinders)
270        {
271            private static final long serialVersionUID = 34L;
272            public boolean evaluate(Object object)
273            {
274                return ((OperationFacade)object).isStatic();
275            }
276        };
277    }
278
279    /**
280     * @return getValueObjectReferences(false)
281     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getValueObjectReferences()
282     */
283    protected Collection<DependencyFacade> handleGetValueObjectReferences()
284    {
285        return this.getValueObjectReferences(false);
286    }
287
288    /**
289     * Retrieves the values object references for this entity.  If
290     * <code>follow</code> is true, then all value object references
291     * (including those that were inherited) will be retrieved.
292     * @param follow
293     * @return ValueObject references
294     */
295    protected Collection<DependencyFacade> getValueObjectReferences(boolean follow)
296    {
297        final Collection<DependencyFacade> sourceDependencies = new ArrayList<DependencyFacade>(this.getSourceDependencies());
298        if (follow)
299        {
300            for (
301                GeneralizableElementFacade entity = this.getGeneralization(); entity != null;
302                entity = entity.getGeneralization())
303            {
304                sourceDependencies.addAll(entity.getSourceDependencies());
305            }
306        }
307        return new FilteredCollection(sourceDependencies)
308        {
309            private static final long serialVersionUID = 34L;
310            public boolean evaluate(Object object)
311            {
312                boolean valid = false;
313                Object targetElement = ((DependencyFacade)object).getTargetElement();
314                if (targetElement instanceof ClassifierFacade)
315                {
316                    ClassifierFacade element = (ClassifierFacade)targetElement;
317                    valid = element.isDataType() || element instanceof ValueObject || element instanceof EnumerationFacade;
318                }
319                return valid;
320            }
321        };
322    }
323
324    /**
325     * @return getValueObjectReferences(true)
326     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getAllValueObjectReferences()
327     */
328    protected Collection<DependencyFacade> handleGetAllValueObjectReferences()
329    {
330        return this.getValueObjectReferences(true);
331    }
332
333    /**
334     * @return IsDaoImplementationRequired
335     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isDaoImplementationRequired()
336     */
337    protected boolean handleIsDaoImplementationRequired()
338    {
339        return !this.getValueObjectReferences().isEmpty() || !this.getDaoBusinessOperations().isEmpty() ||
340        !this.getQueryOperations(true).isEmpty();
341    }
342
343    /**
344     * The suffix given to the no transformation constant. "NONE"
345     */
346    private static final String NO_TRANSFORMATION_CONSTANT_SUFFIX = "NONE";
347
348    /**
349     * @return TRANSFORMATION_CONSTANT_PREFIX + NO_TRANSFORMATION_CONSTANT_SUFFIX
350     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getDaoNoTransformationConstantName()
351     */
352    protected String handleGetDaoNoTransformationConstantName()
353    {
354        return SpringGlobals.TRANSFORMATION_CONSTANT_PREFIX + NO_TRANSFORMATION_CONSTANT_SUFFIX;
355    }
356
357    /**
358     * Common routine to check inheritance.
359     * @param inheritance
360     * @return inheritance.equals(getHibernateInheritanceStrategy())
361     */
362    protected boolean checkHibInheritance(String inheritance)
363    {
364        return inheritance.equals(getHibernateInheritanceStrategy());
365    }
366
367    /**
368     * @return checkHibInheritance(INHERITANCE_STRATEGY_CLASS)
369     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isHibernateInheritanceClass()
370     */
371    protected boolean handleIsHibernateInheritanceClass()
372    {
373        return checkHibInheritance(INHERITANCE_STRATEGY_CLASS);
374    }
375
376    /**
377     * @return checkHibInheritance(INHERITANCE_STRATEGY_INTERFACE)
378     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isHibernateInheritanceInterface()
379     */
380    protected boolean handleIsHibernateInheritanceInterface()
381    {
382        return checkHibInheritance(INHERITANCE_STRATEGY_INTERFACE);
383    }
384
385    /**
386     * @return checkHibInheritance(INHERITANCE_STRATEGY_SUBCLASS)
387     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isHibernateInheritanceSubclass()
388     */
389    protected boolean handleIsHibernateInheritanceSubclass()
390    {
391        return checkHibInheritance(INHERITANCE_STRATEGY_SUBCLASS);
392    }
393
394    /**
395     * @return checkHibInheritance(INHERITANCE_STRATEGY_CONCRETE)
396     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isHibernateInheritanceConcrete()
397     */
398    protected boolean handleIsHibernateInheritanceConcrete()
399    {
400        return checkHibInheritance(INHERITANCE_STRATEGY_CONCRETE);
401    }
402
403    /**
404     * Stores the default hibernate inheritance strategy.
405     */
406    private static final String INHERITANCE_STRATEGY = "hibernateInheritanceStrategy";
407
408    /**
409     * @return superEntity.getHibernateInheritanceStrategy()
410     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getHibernateInheritanceStrategy()
411     */
412    protected String handleGetHibernateInheritanceStrategy()
413    {
414        String inheritance = this.getInheritance(this);
415        for (SpringEntity superEntity = this.getSpringSuperEntity(); superEntity != null && StringUtils.isBlank(inheritance);)
416        {
417            inheritance = superEntity.getHibernateInheritanceStrategy();
418        }
419        inheritance = inheritance != null ? inheritance.toLowerCase() : null;
420        if (StringUtils.isBlank(inheritance) || !INHERITANCE_STRATEGIES.contains(inheritance))
421        {
422            inheritance = this.getDefaultInheritanceStrategy();
423        }
424        return inheritance;
425    }
426
427    /**
428     * Gets the default hibernate inheritance strategy.
429     *
430     * @return the default hibernate inheritance strategy.
431     */
432    private String getDefaultInheritanceStrategy()
433    {
434        return String.valueOf(this.getConfiguredProperty(INHERITANCE_STRATEGY));
435    }
436
437    /**
438     * Return the inheritance tagged value for for given <code>entity</code>.
439     *
440     * @param the SpringEntity from which to retrieve the inheritance tagged value.
441     * @return String inheritance tagged value.
442     */
443    @SuppressWarnings("static-method")
444    private String getInheritance(SpringEntity entity)
445    {
446        String inheritance = null;
447        if (entity != null)
448        {
449            Object value = entity.findTaggedValue(SpringProfile.TAGGEDVALUE_HIBERNATE_INHERITANCE);
450            if (value != null)
451            {
452                inheritance = String.valueOf(value);
453            }
454        }
455        return inheritance;
456    }
457
458    /**
459     * @return IsRequiresHibernateMapping
460     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isRequiresHibernateMapping()
461     */
462    protected boolean handleIsRequiresHibernateMapping()
463    {
464        final SpringEntity superEntity = this.getSpringSuperEntity();
465        return
466            SpringHibernateUtils.mapSubclassesInSeparateFile(
467                (String)this.getConfiguredProperty(SpringGlobals.HIBERNATE_MAPPING_STRATEGY)) ||
468            this.isRoot() &&
469            (
470                !this.isHibernateInheritanceInterface() || this.getSpecializations().isEmpty() ||
471                (superEntity != null && superEntity.isHibernateInheritanceInterface())
472            );
473    }
474
475    /**
476     * Indicates if this entity as a <code>root</code> entity (meaning it doesn't specialize anything).
477     */
478    private boolean isRoot()
479    {
480        final SpringEntity superEntity = this.getSpringSuperEntity();
481        boolean abstractConcreteEntity =
482            (this.isHibernateInheritanceConcrete() || this.isHibernateInheritanceInterface()) && this.isAbstract();
483        return (
484            this.getSpringSuperEntity() == null ||
485            (superEntity.isHibernateInheritanceInterface() || superEntity.isHibernateInheritanceConcrete())
486        ) && !abstractConcreteEntity;
487    }
488
489    /**
490     * Gets the super entity for this entity (if one exists). If a generalization does not exist OR if it's not an
491     * instance of SpringEntity then return null.
492     *
493     * @return the super entity or null if one doesn't exist.
494     */
495    private SpringEntity getSpringSuperEntity()
496    {
497        SpringEntity superEntity = null;
498        if (this.getGeneralization() != null && this.getGeneralization() instanceof SpringEntity)
499        {
500            superEntity = (SpringEntity)this.getGeneralization();
501        }
502        return superEntity;
503    }
504
505    /**
506     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#getAttributeEmbeddedValueList()
507     */
508    @Override
509    protected String handleGetAttributeEmbeddedValueList()
510    {
511        final StringBuilder buffer = new StringBuilder();
512        for (final Iterator<AttributeFacade> iterator = this.getEmbeddedValues().iterator(); iterator.hasNext();)
513        {
514            final AttributeFacade attribute = iterator.next();
515            final String name = attribute.getName();
516            if (StringUtils.isNotBlank(name))
517            {
518                buffer.append('\"').append(name).append('\"');
519                if (iterator.hasNext())
520                {
521                    buffer.append(", ");
522                }
523            }
524        }
525        return buffer.toString();
526    }
527
528    /**
529     * @return StringUtils.trimToEmpty(String.valueOf(this.getConfiguredProperty("richClient"))).equalsIgnoreCase("true")
530     * @see org.andromda.cartridges.spring.metafacades.SpringEntity#isRichClient()
531     */
532    protected boolean handleIsRichClient()
533    {
534        String richClient =
535            StringUtils.trimToEmpty(String.valueOf(this.getConfiguredProperty("richClient")));
536
537        return "true".equalsIgnoreCase(richClient);
538    }
539
540    /**
541     * Helper function "searchUnique" + capitalize(attributeName)
542     * @param attributeName 
543     * @return searchUnique function name
544     */
545    public String getSearchUniqueFunctionName(String attributeName)
546    {
547        return "searchUnique"+StringUtils.capitalize(attributeName);
548    }
549    
550}