001package org.andromda.cartridges.ejb.metafacades;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.Iterator;
007import java.util.List;
008import org.andromda.cartridges.ejb.EJBGlobals;
009import org.andromda.cartridges.ejb.EJBProfile;
010import org.andromda.core.common.ExceptionRecorder;
011import org.andromda.metafacades.uml.AttributeFacade;
012import org.andromda.metafacades.uml.ClassifierFacade;
013import org.andromda.metafacades.uml.DependencyFacade;
014import org.andromda.metafacades.uml.MetafacadeUtils;
015import org.andromda.metafacades.uml.ModelElementFacade;
016import org.andromda.metafacades.uml.OperationFacade;
017import org.andromda.metafacades.uml.TypeMappings;
018import org.andromda.metafacades.uml.UMLMetafacadeProperties;
019import org.apache.commons.collections.CollectionUtils;
020import org.apache.commons.collections.Predicate;
021import org.apache.commons.lang.StringUtils;
022import org.apache.log4j.Logger;
023
024/**
025 * <p>
026 * Represents an entity EJB. </p> Metaclass facade implementation.
027 * @author Bob Fields
028 */
029public class EJBEntityFacadeLogicImpl
030    extends EJBEntityFacadeLogic
031{
032    private static final long serialVersionUID = 34L;
033    // ---------------- constructor -------------------------------
034    /**
035     * @param metaObject
036     * @param context
037     */
038    public EJBEntityFacadeLogicImpl(
039        Object metaObject,
040        String context)
041    {
042        super(metaObject, context);
043    }
044
045    /**
046     * The logger instance.
047     */
048    private static final Logger logger = Logger.getLogger(EJBEntityFacadeLogicImpl.class);
049
050    /**
051     * @return identifiers
052     */
053    public Collection handleGetIdentifiers()
054    {
055        Collection identifiers = new ArrayList();
056        Iterator iter = this.getSourceDependencies().iterator();
057        while (iter.hasNext())
058        {
059            DependencyFacade dep = (DependencyFacade)iter.next();
060            if (dep.hasStereotype(EJBProfile.STEREOTYPE_IDENTIFIER))
061            {
062                identifiers = ((ClassifierFacade)dep.getTargetElement()).getInstanceAttributes();
063                MetafacadeUtils.filterByStereotype(
064                    identifiers,
065                    EJBProfile.STEREOTYPE_IDENTIFIER);
066                return identifiers;
067            }
068        }
069
070        // No PK dependency found - try a PK attribute
071        if (super.getIdentifiers() != null && !super.getIdentifiers().isEmpty())
072        {
073            AttributeFacade attr = (AttributeFacade)super.getIdentifiers().iterator().next();
074            identifiers.add(attr);
075            return identifiers;
076        }
077
078        // Still nothing found - recurse up the inheritance tree
079        EJBEntityFacade decorator = (EJBEntityFacade)this.getGeneralization();
080        return decorator.getIdentifiers();
081    }
082
083    /**
084     * @return getEntityRelations()
085     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getAllEntityRelations()
086     */
087    protected Collection handleGetAllEntityRelations()
088    {
089        // Only concrete entities may have EJB relations. Return
090        // an empty collection for everything else
091        if (this.isAbstract())
092        {
093            return Collections.emptyList();
094        }
095        Collection result = new ArrayList();
096        result.addAll(getEntityRelations());
097        ClassifierFacade classifier = (ClassifierFacade)this.getGeneralization();
098        while (classifier != null && classifier instanceof EJBEntityFacade && classifier.isAbstract())
099        {
100            EJBEntityFacade entity = (EJBEntityFacade)classifier;
101            result.addAll(entity.getEntityRelations());
102            classifier = (ClassifierFacade)classifier.getGeneralization();
103        }
104        return result;
105    }
106
107    /**
108     * @return EJBMetafacadeUtils.getViewType(this)
109     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getViewType()
110     */
111    protected String handleGetViewType()
112    {
113        return EJBMetafacadeUtils.getViewType(this);
114    }
115
116    /**
117     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetEntityRelations()
118     */
119    protected Collection handleGetEntityRelations()
120    {
121        Collection result = new ArrayList();
122        for (final Iterator iterator = this.getAssociationEnds().iterator(); iterator.hasNext();)
123        {
124            EJBAssociationEndFacade associationEnd = (EJBAssociationEndFacade)iterator.next();
125            ClassifierFacade target = associationEnd.getOtherEnd().getType();
126            if (target instanceof EJBEntityFacade && associationEnd.getOtherEnd().isNavigable())
127            {
128                // Check the integrity constraint
129                Object value =
130                    associationEnd.getOtherEnd().getAssociation().findTaggedValue(EJBProfile.TAGGEDVALUE_GENERATE_CMR);
131                String generateCmr = value == null ? null : value.toString();
132                if (target.isAbstract() && !"false".equalsIgnoreCase(generateCmr))
133                {
134                    throw new IllegalStateException("Relation '" + associationEnd.getAssociation().getName() +
135                        "' has the abstract target '" + target.getName() +
136                        "'. Abstract targets are not allowed in EJB.");
137                }
138                result.add(associationEnd);
139            }
140        }
141
142        return result;
143    }
144
145    /**
146     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetAllInstanceAttributes()
147     */
148    protected List handleGetAllInstanceAttributes()
149    {
150        return EJBMetafacadeUtils.getAllInstanceAttributes(this);
151    }
152
153    /**
154     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetInheritedInstanceAttributes()
155     */
156    protected List handleGetInheritedInstanceAttributes()
157    {
158        return EJBMetafacadeUtils.getInheritedInstanceAttributes(this);
159    }
160
161    /**
162     * @param follow
163     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetCreateMethods(boolean)
164     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getCreateMethods(boolean)
165     */
166    protected Collection handleGetCreateMethods(boolean follow)
167    {
168        return EJBMetafacadeUtils.getCreateMethods(
169            this,
170            follow);
171    }
172
173    /**
174     * @param follow
175     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetSelectMethods(boolean)
176     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getSelectMethods(boolean)
177     */
178    protected Collection handleGetSelectMethods(boolean follow)
179    {
180        Collection retval = new ArrayList();
181        EJBEntityFacade entity = null;
182        do
183        {
184            Collection ops = this.getOperations();
185            for (final Iterator i = ops.iterator(); i.hasNext();)
186            {
187                OperationFacade op = (OperationFacade)i.next();
188                if (op.hasStereotype(EJBProfile.STEREOTYPE_SELECT_METHOD))
189                {
190                    retval.add(op);
191                }
192            }
193            if (follow)
194            {
195                entity = (EJBEntityFacade)this.getGeneralization();
196            }
197            else
198            {
199                break;
200            }
201        }
202        while (entity != null);
203        return retval;
204    }
205
206    /**
207     * @return getHomeInterfaceName
208     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getHomeInterfaceName()
209     */
210    protected String handleGetHomeInterfaceName()
211    {
212        return EJBMetafacadeUtils.getHomeInterfaceName(this);
213    }
214
215    /**
216     * @param follow
217     * @return getEnvironmentEntries
218     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getEnvironmentEntries(boolean)
219     */
220    protected Collection handleGetEnvironmentEntries(boolean follow)
221    {
222        return EJBMetafacadeUtils.getEnvironmentEntries(
223            this,
224            follow);
225    }
226
227    /**
228     * @param follow
229     * @return getConstants
230     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getConstants(boolean)
231     */
232    protected Collection handleGetConstants(boolean follow)
233    {
234        return EJBMetafacadeUtils.getConstants(
235            this,
236            follow);
237    }
238
239    /**
240     * @return jndiName
241     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacade#getJndiName()
242     */
243    protected String handleGetJndiName()
244    {
245        StringBuilder jndiName = new StringBuilder();
246        String jndiNamePrefix = StringUtils.trimToEmpty(this.getJndiNamePrefix());
247        if (StringUtils.isNotBlank(jndiNamePrefix))
248        {
249            jndiName.append(jndiNamePrefix);
250            jndiName.append('/');
251        }
252        jndiName.append("ejb/");
253        jndiName.append(this.getFullyQualifiedName());
254        return jndiName.toString();
255    }
256
257    /**
258     * Gets the <code>jndiNamePrefix</code> for this EJB.
259     *
260     * @return the EJB Jndi name prefix.
261     */
262    protected String getJndiNamePrefix()
263    {
264        String prefix = null;
265        if (this.isConfiguredProperty(EJBGlobals.JNDI_NAME_PREFIX))
266        {
267            prefix = (String)this.getConfiguredProperty(EJBGlobals.JNDI_NAME_PREFIX);
268        }
269        return prefix;
270    }
271
272    /**
273     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleIsSyntheticCreateMethodAllowed()
274     */
275    protected boolean handleIsSyntheticCreateMethodAllowed()
276    {
277        return EJBMetafacadeUtils.allowSyntheticCreateMethod(this);
278    }
279
280    /**
281     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#getBusinessOperations()
282     */
283    // TODO: Change return type to Collection<EJBOperationFacade> (metamodel change)
284    public Collection<OperationFacade> getBusinessOperations()
285    {
286        Collection<OperationFacade> businessOperations = new ArrayList<OperationFacade>();
287        for (OperationFacade operation : super.getBusinessOperations())
288        {
289            if (EJBOperationFacade.class.isAssignableFrom(operation.getClass()))
290            {
291                EJBOperationFacade businessOperation = (EJBOperationFacade)operation;
292                if (businessOperation.isBusinessOperation())
293                {
294                    businessOperations.add(businessOperation);
295                }
296            }
297        }
298        return businessOperations;
299    }
300
301    /**
302     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetValueDependencies()
303     */
304    protected Collection handleGetValueDependencies()
305    {
306        Collection dependencies = super.getSourceDependencies();
307        CollectionUtils.filter(
308            dependencies,
309            new Predicate()
310            {
311                public boolean evaluate(Object object)
312                {
313                    boolean isValueRef = false;
314                    if (object instanceof DependencyFacade)
315                    {
316                        DependencyFacade dep = (DependencyFacade)object;
317                        isValueRef =
318                            dep.getStereotypeNames().contains(EJBProfile.STEREOTYPE_VALUE_REF) &&
319                            dep.getTargetElement().hasExactStereotype(EJBProfile.STEREOTYPE_VALUE_OBJECT);
320                    }
321                    return isValueRef;
322                }
323            });
324        return dependencies;
325    }
326
327    /**
328     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleIsIdentifierPresent(String)
329     */
330    protected boolean handleIsIdentifierPresent(String identifier)
331    {
332        for (ModelElementFacade attr : this.getIdentifiers(true))
333        {
334            if (attr.getName().equalsIgnoreCase(identifier))
335            {
336                return true;
337            }
338        }
339        return false;
340    }
341
342    /**
343     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleIsAttributePresent(String)
344     */
345    protected boolean handleIsAttributePresent(String strAttr)
346    {
347        Collection<AttributeFacade> collAttrib = this.getAttributes(true);
348        for (AttributeFacade attr : collAttrib)
349        {
350            if (attr.getName().equalsIgnoreCase(strAttr))
351            {
352                return true;
353            }
354        }
355        return false;
356    }
357
358    /**
359     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleIsOperationPresent(String)
360     */
361    protected boolean handleIsOperationPresent(String op)
362    {
363        Collection<OperationFacade> collOps = this.getOperations();
364        for (OperationFacade operation : collOps)
365        {
366            if (operation.getName().equalsIgnoreCase(op))
367            {
368                return true;
369            }
370        }
371        return false;
372    }
373
374    /**
375     * Gets a Mappings instance from a property registered under the given <code>propertyName</code>.
376     *
377     * @param propertyName the property name to register under.
378     * @return the Mappings instance.
379     */
380    private TypeMappings getMappingsProperty(final String propertyName)
381    {
382        Object property = this.getConfiguredProperty(propertyName);
383        TypeMappings mappings = null;
384        String uri = null;
385        if (property instanceof String)
386        {
387            uri = (String)property;
388            try
389            {
390                mappings = TypeMappings.getInstance(uri);
391                this.setProperty(
392                    propertyName,
393                    mappings);
394            }
395            catch (Throwable th)
396            {
397                String errMsg = "Error getting '" + propertyName + "' --> '" + uri + '\'';
398                logger.error(errMsg);
399                // don't throw the exception
400                ExceptionRecorder.instance().record(
401                    errMsg,
402                    th);
403            }
404        }
405        else
406        {
407            mappings = (TypeMappings)property;
408        }
409        return mappings;
410    }
411
412    /**
413     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetSqlType()
414     */
415    protected String handleGetSqlType()
416    {
417        String mpSql = this.getMappingsProperty(UMLMetafacadeProperties.SQL_MAPPINGS_URI).getMappings().getName();
418        if (mpSql.startsWith("Oracle"))
419        {
420            mpSql = "ORACLE";
421        }
422        return mpSql;
423    }
424
425    /**
426     * @see org.andromda.cartridges.ejb.metafacades.EJBEntityFacadeLogic#handleGetTransactionType()
427     */
428    protected String handleGetTransactionType()
429    {
430        String transactionType = (String)this.findTaggedValue(EJBProfile.TAGGEDVALUE_EJB_TRANSACTION_TYPE);
431        if (StringUtils.isBlank(transactionType))
432        {
433            transactionType = String.valueOf(this.getConfiguredProperty(EJBGlobals.TRANSACTION_TYPE));
434        }
435        return transactionType;
436    }
437}