StrutsUseCaseLogicImpl.java

package org.andromda.cartridges.bpm4struts.metafacades;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import org.andromda.cartridges.bpm4struts.Bpm4StrutsGlobals;
import org.andromda.cartridges.bpm4struts.Bpm4StrutsProfile;
import org.andromda.cartridges.bpm4struts.Bpm4StrutsUtils;
import org.andromda.metafacades.uml.ActionStateFacade;
import org.andromda.metafacades.uml.ActivityGraphFacade;
import org.andromda.metafacades.uml.FinalStateFacade;
import org.andromda.metafacades.uml.FrontEndActivityGraph;
import org.andromda.metafacades.uml.FrontEndParameter;
import org.andromda.metafacades.uml.FrontEndUseCase;
import org.andromda.metafacades.uml.FrontEndView;
import org.andromda.metafacades.uml.Role;
import org.andromda.utils.StringUtilsHelper;
import org.apache.commons.lang.StringUtils;

/**
 * MetafacadeLogic implementation.
 *
 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase
 */
public class StrutsUseCaseLogicImpl
    extends StrutsUseCaseLogic
{
    private static final long serialVersionUID = 34L;
    /**
     * @param metaObject
     * @param context
     */
    public StrutsUseCaseLogicImpl(
        Object metaObject,
        String context)
    {
        super(metaObject, context);
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleKey()
     */
    protected String handleGetTitleKey()
    {
        return StringUtilsHelper.toResourceMessageKey(normalizeMessages() ? getTitleValue() : getName()) + ".title";
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleValue()
     */
    protected String handleGetTitleValue()
    {
        return StringUtilsHelper.toPhrase(getName());
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpKey()
     */
    protected String handleGetOnlineHelpKey()
    {
        return StringUtilsHelper.toResourceMessageKey(getName()) + ".online.help";
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpValue()
     */
    protected String handleGetOnlineHelpValue()
    {
        final String crlf = "<br/>";
        final StringBuilder buffer = new StringBuilder();

        buffer.append(!this.isDocumentationPresent() ? "No use-case documentation has been specified"
            : StringUtilsHelper.toResourceMessage(this.getDocumentation("", 64, false)));
        buffer.append(crlf);

        return StringUtilsHelper.toResourceMessage(buffer.toString());
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionPath()
     */
    protected String handleGetActionPath()
    {
        String actionPath = null;

        final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
        if (graph != null)
        {
            final StrutsAction action = graph.getFirstAction();
            if (action != null)
            {
                actionPath = action.getActionPath();
            }
        }
        return actionPath;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionPathRoot()
     */
    protected String handleGetActionPathRoot()
    {
        String actionPathRoot = null;

        final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
        if (graph != null)
        {
            final StrutsAction action = graph.getFirstAction();
            if (action != null)
            {
                actionPathRoot = action.getActionPathRoot();
            }
        }
        return actionPathRoot;
    }

    /**
     * @return isCyclic
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase#isCyclic()
     */
    protected boolean handleIsCyclic()
    {
        boolean selfTargetting = false;
        final ActivityGraphFacade graph = getActivityGraph();
        if (graph != null)
        {
            final Collection<FinalStateFacade> finalStates = graph.getFinalStates();
            for (final Iterator finalStateIterator = finalStates.iterator();
                 finalStateIterator.hasNext() && !selfTargetting;)
            {
                final StrutsFinalState finalState = (StrutsFinalState)finalStateIterator.next();
                if (this.equals(finalState.getTargetUseCase()))
                {
                    selfTargetting = true;
                }
            }
        }
        return selfTargetting;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionRoles()
     */
    protected String handleGetActionRoles()
    {
        final Collection<Role> users = this.getRoles();
        final StringBuilder rolesBuffer = new StringBuilder();
        boolean first = true;
        for (final Iterator<Role> userIterator = users.iterator(); userIterator.hasNext();)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                rolesBuffer.append(',');
            }
            final Role role = userIterator.next();
            rolesBuffer.append(role.getName());
        }
        return rolesBuffer.toString();
    }

    /**
     * Collections.EMPTY_LIST
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#getOperations()
     */
    public List getOperations()
    {
        return Collections.emptyList();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetPages()
     */
    protected List<FrontEndView> handleGetPages()
    {
        return this.getViews();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetAllPages()
     */
    protected List<StrutsJsp> handleGetAllPages()
    {
        final List<StrutsJsp> pagesList = new ArrayList<StrutsJsp>();
        for (final ActionStateFacade actionState : getModel().getAllActionStates())
        {
            if (actionState instanceof StrutsJsp)
                pagesList.add((StrutsJsp)actionState);
        }
        return pagesList;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetFormFields()
     */
    protected List handleGetFormFields()
    {
        final List formFields = new ArrayList(); // parameter names are supposed to be unique

        for (final StrutsJsp jsp : getPages())
        {
            for (final StrutsParameter parameter : jsp.getPageVariables())
            {
                formFields.add(parameter);
            }
            for (final FrontEndParameter parameter : jsp.getAllActionParameters())
            {
                formFields.add(parameter);
            }
        }
        return formFields;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsValidationRequired()
     */
    protected boolean handleIsValidationRequired()
    {
        for (final StrutsJsp jsp : this.getAllPages())
        {
            if (jsp.isValidationRequired())
            {
                return true;
            }
        }
        return false;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsApplicationValidationRequired()
     */
    protected boolean handleIsApplicationValidationRequired()
    {
        for (final FrontEndUseCase useCase : this.getAllUseCases())
        {
            if (((StrutsUseCase)useCase).isValidationRequired())
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Overridden because StrutsAction does not extend FrontEndAction.
     *
     * @see org.andromda.metafacades.uml.FrontEndUseCase#getActions()
     */
    public List getActions()
    {
        final Collection actions = new LinkedHashSet();

        for (final StrutsJsp jsp : getPages())
        {
            actions.addAll(jsp.getActions());
        }

        final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
        if (graph != null)
        {
            final StrutsAction action = graph.getFirstAction();
            if (action != null) actions.add(action);
        }

        return new ArrayList(actions);
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetPageVariables()
     */
    protected List<FrontEndParameter>  handleGetPageVariables()
    {
        return this.getViewVariables();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsApplicationUseCase()
     */
    protected boolean handleIsApplicationUseCase()
    {
        return this.isEntryUseCase();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetCssFileName()
     */
    protected String handleGetCssFileName()
    {
        return this.getPackagePath() + '/' + Bpm4StrutsUtils.toWebFileName(this.getName()) + ".css";
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetApplicationHierarchyRoot()
     */
    protected TreeNode handleGetApplicationHierarchyRoot()
    {
        final UseCaseNode root = new UseCaseNode(this);
        this.createHierarchy(root);
        return root;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetHierarchyRoot()
     */
    protected TreeNode handleGetHierarchyRoot()
    {
        UseCaseNode hierarchy = null;

        final Collection<FrontEndUseCase> allUseCases = this.getAllUseCases();
        for (final Iterator<FrontEndUseCase> useCaseIterator = allUseCases.iterator(); useCaseIterator.hasNext();)
        {
            final StrutsUseCase useCase = (StrutsUseCase)useCaseIterator.next();
            if (useCase.isApplicationUseCase())
            {
                final UseCaseNode root = (UseCaseNode)useCase.getApplicationHierarchyRoot();
                hierarchy = this.findNode(root, this);
            }
        }
        return hierarchy;
    }

    /**
     * Recursively creates a hierarchy of use-cases, starting with the argument use-case as the root. This is primarily
     * meant to build a set of menu items.
     */
    private void createHierarchy(UseCaseNode root)
    {
        final StrutsUseCase useCase = (StrutsUseCase)root.getUserObject();

        final FrontEndActivityGraph graph = useCase.getActivityGraph();
        if (graph != null)
        {
            final Collection<FinalStateFacade> finalStates = graph.getFinalStates();
            for (final Iterator<FinalStateFacade> finalStateIterator = finalStates.iterator(); finalStateIterator.hasNext();)
            {
                final StrutsFinalState finalState = (StrutsFinalState)finalStateIterator.next();
                final StrutsUseCase targetUseCase = (StrutsUseCase)finalState.getTargetUseCase();
                if (targetUseCase != null)
                {
                    final UseCaseNode useCaseNode = new UseCaseNode(targetUseCase);
                    if (!isNodeAncestor(root, useCaseNode))
                    {
                        root.add(useCaseNode);
                        createHierarchy(useCaseNode);
                    }
                }
            }
        }
    }

    /**
     * <code>true</code> if the argument ancestor node is actually an ancestor of the first node.
     * <p>
     * <em>Note: DefaultMutableTreeNode's isNodeAncestor does not work because of its specific impl.</em>
     */
    private boolean isNodeAncestor(
        UseCaseNode node,
        UseCaseNode ancestorNode)
    {
        boolean ancestor = false;

        if (node.getUseCase().equals(ancestorNode.getUseCase()))
        {
            ancestor = true;
        }
        while (!ancestor && node.getParent() != null)
        {
            node = (UseCaseNode)node.getParent();
            if (this.isNodeAncestor(node, ancestorNode))
            {
                ancestor = true;
            }
        }
        return ancestor;
    }

    /**
     * Given a root use-case, finds the node in the hierarchy that represent the argument StrutsUseCase node.
     */
    private UseCaseNode findNode(
        UseCaseNode root,
        StrutsUseCase useCase)
    {
        UseCaseNode useCaseNode = null;

        final List<UseCaseNode> nodeList = Collections.list(root.breadthFirstEnumeration());
        for (final Iterator<UseCaseNode> nodeIterator = nodeList.iterator(); nodeIterator.hasNext() && useCaseNode == null;)
        {
            UseCaseNode node = nodeIterator.next();
            if (useCase.equals(node.getUserObject()))
            {
                useCaseNode = node;
            }
        }
        return useCaseNode;
    }

    /**
     *
     */
    public static final class UseCaseNode
        extends DefaultMutableTreeNode
    {
        /**
         * Automatically generated variable: serialVersionUID
         */
        private static final long serialVersionUID = -4839356733341754931L;

        /**
         * @param useCase
         */
        public UseCaseNode(StrutsUseCase useCase)
        {
            super(useCase);
        }

        /**
         * @return getUserObject()
         */
        public StrutsUseCase getUseCase()
        {
            return (StrutsUseCase)getUserObject();
        }
    }

    private boolean normalizeMessages()
    {
        final String normalizeMessages = (String)getConfiguredProperty(Bpm4StrutsGlobals.PROPERTY_NORMALIZE_MESSAGES);
        return Boolean.valueOf(normalizeMessages).booleanValue();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetAllMessages()
     */
    protected Map handleGetAllMessages()
    {
        final boolean normalize = this.normalizeMessages();
        final Map<String, String> messages = (normalize) ? new TreeMap() : new LinkedHashMap<String, String>();

        if (this.isApplicationUseCase())
        {
            final List<FrontEndUseCase> useCases = this.getAllUseCases();
            for (int i = 0; i < useCases.size(); i++)
            {
                // USECASE
                final StrutsUseCase useCase = (StrutsUseCase)useCases.get(i);
                messages.put(useCase.getTitleKey(), useCase.getTitleValue());
                messages.put(useCase.getOnlineHelpKey(), useCase.getOnlineHelpValue());

                final List actions = useCase.getActions();
                for (int j = 0; j < actions.size(); j++)
                {
                    final StrutsAction action = (StrutsAction)actions.get(j);

                    // FORWARDS
                    for (StrutsForward forward : action.getTransitions())
                    {
                        messages.putAll(forward.getSuccessMessages());
                        messages.putAll(forward.getWarningMessages());
                    }

                    // EXCEPTION FORWARDS
                    final List<StrutsExceptionHandler> exceptions = action.getActionExceptions();

                    if (normalize)
                    {
                        if (exceptions.isEmpty())
                        {
                            if (!action.isUseCaseStart())
                            {
                                messages.put(action.getMessageKey() + ".exception", "{0} (java.lang.Exception)");
                            }
                        }
                        else
                        {
                            for (final StrutsExceptionHandler exception : exceptions)
                            {
                                messages.put(action.getMessageKey() + '.' + exception.getExceptionKey(), "{0}");
                            }
                        }
                    }
                    else
                    {
                        if (exceptions.isEmpty())
                        {
                            if (!action.isUseCaseStart())
                            {
                                messages.put(action.getMessageKey() + ".exception", "{0} (java.lang.Exception)");
                            }
                        }
                        else
                        {
                            for (int l = 0; l < exceptions.size(); l++)
                            {
                                final StrutsExceptionHandler exception = exceptions.get(l);
                                // we construct the key using the action message too because the exception can
                                // belong to more than one action (therefore it cannot return the correct value
                                // in .getExceptionKey())
                                messages.put(action.getMessageKey() + '.' + exception.getExceptionKey(),
                                    "{0} (" + exception.getExceptionType() + ')');
                            }
                        }
                    }

                    // TRIGGER
                    final StrutsTrigger trigger = action.getActionTrigger();
                    if (trigger != null)
                    {
                        // only add these when a trigger is present, otherwise it's no use having them
                        messages.put(action.getOnlineHelpKey(), action.getOnlineHelpValue());
                        messages.put(action.getDocumentationKey(), action.getDocumentationValue());

                        // the regular trigger messages
                        messages.put(trigger.getTitleKey(), trigger.getTitleValue());
                        messages.put(trigger.getNotAllowedTitleKey(), trigger.getNotAllowedTitleValue());
                        messages.put(trigger.getResetMessageKey(), trigger.getResetMessageValue());
                        messages.put(trigger.getResetNotAllowedTitleKey(), trigger.getResetNotAllowedTitleValue());
                        messages.put(trigger.getResetTitleKey(), trigger.getResetTitleValue());
                        // this one is the same as doing: action.getMessageKey()
                        messages.put(trigger.getTriggerKey(), trigger.getTriggerValue());

                        // IMAGE LINK
                        if (action.isImageLink())
                        {
                            messages.put(action.getImageMessageKey(), action.getImagePath());
                        }
                    }
                }

                final List pages = useCase.getPages();
                for (int j = 0; j < pages.size(); j++)
                {
                    // PAGE
                    final StrutsJsp page = (StrutsJsp)pages.get(j);
                    messages.put(page.getTitleKey(), page.getTitleValue());
                    messages.put(page.getMessageKey(), page.getMessageValue());
                    messages.put(page.getOnlineHelpKey(), page.getOnlineHelpValue());
                    messages.put(page.getDocumentationKey(), page.getDocumentationValue());

                    final List<StrutsParameter> pageVariables = page.getPageVariables();
                    for (int k = 0; k < pageVariables.size(); k++)
                    {
                        // PAGE-VARIABLE
                        final StrutsParameter parameter = pageVariables.get(k);

                        messages.put(parameter.getMessageKey(), parameter.getMessageValue());
/*
                        if (normalize)
                        {
                            // the next line is in comment because it's not actually being used
                            //messages.put(parameter.getTitleKey(), parameter.getTitleValue());
                            messages.put(parameter.getMessageKey(), parameter.getMessageValue());
                        }
                        else
                        {
                            // the next line is in comment because it's not actually being used
                            //messages.put(page.getTitleKey() + '.' + parameter.getTitleKey(), parameter.getTitleValue());
                            messages.put(page.getTitleKey() + '.' + parameter.getMessageKey(),
                                    parameter.getMessageValue());
                        }
*/

                        // TABLE
                        if (parameter.isTable())
                        {
                            final Collection<String> columnNames = parameter.getTableColumnNames();
                            for (final Iterator columnNameIterator = columnNames.iterator();
                                 columnNameIterator.hasNext();)
                            {
                                final String columnName = (String)columnNameIterator.next();
                                messages.put(parameter.getTableColumnMessageKey(columnName),
                                    parameter.getTableColumnMessageValue(columnName));
                            }
                        }
                    }

                    for (int k = 0; k < actions.size(); k++)
                    {
                        // ACTION
                        final StrutsAction action = (StrutsAction)actions.get(k);

                        // ACTION PARAMETERS
                        final List parameters = action.getActionParameters();
                        for (int l = 0; l < parameters.size(); l++)
                        {
                            final StrutsParameter parameter = (StrutsParameter)parameters.get(l);
                            messages.put(parameter.getMessageKey(), parameter.getMessageValue());
                            messages.put(parameter.getOnlineHelpKey(), parameter.getOnlineHelpValue());
                            messages.put(parameter.getDocumentationKey(), parameter.getDocumentationValue());
                            messages.put(parameter.getTitleKey(), parameter.getTitleValue());

                            if (parameter.getValidWhen() != null)
                            {
                                // this key needs to be fully qualified since the valid when value can be different
                                final String completeKeyPrefix = (normalize)
                                    ? parameter.getMessageKey()
                                    : useCase.getTitleKey() + '.' +
                                    page.getMessageKey() + '.' +
                                    action.getMessageKey() + '.' +
                                    parameter.getMessageKey();
                                messages.put(completeKeyPrefix + "_validwhen",
                                    "{0} is only valid when " + parameter.getValidWhen());
                            }

                            if (parameter.getOptionCount() > 0)
                            {
                                final List optionKeys = parameter.getOptionKeys();
                                final List optionValues = parameter.getOptionValues();

                                for (int m = 0; m < optionKeys.size(); m++)
                                {
                                    messages.put((String)optionKeys.get(m), (String)optionValues.get(m));
                                    messages.put((String)optionKeys.get(m) + ".title", (String)optionValues.get(m));
                                }
                            }
                        }
                    }
                }
            }
        }

        return messages;
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpPagePath()
     */
    protected String handleGetOnlineHelpPagePath()
    {
        final StringBuilder buffer = new StringBuilder();

        if (StringUtils.isNotBlank(this.getPackagePath()))
        {
            buffer.append('/');
            buffer.append(this.getPackagePath());
        }
        buffer.append('/');
        buffer.append(StringUtilsHelper.separate(this.getName(), "-"));
        buffer.append("_help");

        return buffer.toString();
    }

    /**
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpActionPath()
     */
    protected String handleGetOnlineHelpActionPath()
    {
        final StringBuilder buffer = new StringBuilder();

        if (StringUtils.isNotBlank(this.getPackagePath()))
        {
            buffer.append('/');
            buffer.append(this.getPackagePath());
        }
        buffer.append('/');
        buffer.append(StringUtilsHelper.upperCamelCaseName(this.getName()));
        buffer.append("Help");

        return buffer.toString();
    }

    /**
     * @return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_KEY
     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase#getFormKey()
     */
    protected String handleGetFormKey()
    {
        final Object formKeyValue = this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_KEY);
        return formKeyValue == null
            ? Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_DEFAULT_KEY
            : String.valueOf(formKeyValue);
    }
}