View Javadoc
1   package org.andromda.cartridges.bpm4struts.metafacades;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.Iterator;
7   import java.util.LinkedHashMap;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.TreeMap;
12  import javax.swing.tree.DefaultMutableTreeNode;
13  import javax.swing.tree.TreeNode;
14  import org.andromda.cartridges.bpm4struts.Bpm4StrutsGlobals;
15  import org.andromda.cartridges.bpm4struts.Bpm4StrutsProfile;
16  import org.andromda.cartridges.bpm4struts.Bpm4StrutsUtils;
17  import org.andromda.metafacades.uml.ActionStateFacade;
18  import org.andromda.metafacades.uml.ActivityGraphFacade;
19  import org.andromda.metafacades.uml.FinalStateFacade;
20  import org.andromda.metafacades.uml.FrontEndActivityGraph;
21  import org.andromda.metafacades.uml.FrontEndParameter;
22  import org.andromda.metafacades.uml.FrontEndUseCase;
23  import org.andromda.metafacades.uml.FrontEndView;
24  import org.andromda.metafacades.uml.Role;
25  import org.andromda.utils.StringUtilsHelper;
26  import org.apache.commons.lang.StringUtils;
27  
28  /**
29   * MetafacadeLogic implementation.
30   *
31   * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase
32   */
33  public class StrutsUseCaseLogicImpl
34      extends StrutsUseCaseLogic
35  {
36      private static final long serialVersionUID = 34L;
37      /**
38       * @param metaObject
39       * @param context
40       */
41      public StrutsUseCaseLogicImpl(
42          Object metaObject,
43          String context)
44      {
45          super(metaObject, context);
46      }
47  
48      /**
49       * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleKey()
50       */
51      protected String handleGetTitleKey()
52      {
53          return StringUtilsHelper.toResourceMessageKey(normalizeMessages() ? getTitleValue() : getName()) + ".title";
54      }
55  
56      /**
57       * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleValue()
58       */
59      protected String handleGetTitleValue()
60      {
61          return StringUtilsHelper.toPhrase(getName());
62      }
63  
64      /**
65       * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpKey()
66       */
67      protected String handleGetOnlineHelpKey()
68      {
69          return StringUtilsHelper.toResourceMessageKey(getName()) + ".online.help";
70      }
71  
72      /**
73       * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpValue()
74       */
75      protected String handleGetOnlineHelpValue()
76      {
77          final String crlf = "<br/>";
78          final StringBuilder buffer = new StringBuilder();
79  
80          buffer.append(!this.isDocumentationPresent() ? "No use-case documentation has been specified"
81              : StringUtilsHelper.toResourceMessage(this.getDocumentation("", 64, false)));
82          buffer.append(crlf);
83  
84          return StringUtilsHelper.toResourceMessage(buffer.toString());
85      }
86  
87      /**
88       * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionPath()
89       */
90      protected String handleGetActionPath()
91      {
92          String actionPath = null;
93  
94          final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
95          if (graph != null)
96          {
97              final StrutsAction action = graph.getFirstAction();
98              if (action != null)
99              {
100                 actionPath = action.getActionPath();
101             }
102         }
103         return actionPath;
104     }
105 
106     /**
107      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionPathRoot()
108      */
109     protected String handleGetActionPathRoot()
110     {
111         String actionPathRoot = null;
112 
113         final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
114         if (graph != null)
115         {
116             final StrutsAction action = graph.getFirstAction();
117             if (action != null)
118             {
119                 actionPathRoot = action.getActionPathRoot();
120             }
121         }
122         return actionPathRoot;
123     }
124 
125     /**
126      * @return isCyclic
127      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase#isCyclic()
128      */
129     protected boolean handleIsCyclic()
130     {
131         boolean selfTargetting = false;
132         final ActivityGraphFacade graph = getActivityGraph();
133         if (graph != null)
134         {
135             final Collection<FinalStateFacade> finalStates = graph.getFinalStates();
136             for (final Iterator finalStateIterator = finalStates.iterator();
137                  finalStateIterator.hasNext() && !selfTargetting;)
138             {
139                 final StrutsFinalState finalState = (StrutsFinalState)finalStateIterator.next();
140                 if (this.equals(finalState.getTargetUseCase()))
141                 {
142                     selfTargetting = true;
143                 }
144             }
145         }
146         return selfTargetting;
147     }
148 
149     /**
150      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionRoles()
151      */
152     protected String handleGetActionRoles()
153     {
154         final Collection<Role> users = this.getRoles();
155         final StringBuilder rolesBuffer = new StringBuilder();
156         boolean first = true;
157         for (final Iterator<Role> userIterator = users.iterator(); userIterator.hasNext();)
158         {
159             if (first)
160             {
161                 first = false;
162             }
163             else
164             {
165                 rolesBuffer.append(',');
166             }
167             final Role role = userIterator.next();
168             rolesBuffer.append(role.getName());
169         }
170         return rolesBuffer.toString();
171     }
172 
173     /**
174      * Collections.EMPTY_LIST
175      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#getOperations()
176      */
177     public List getOperations()
178     {
179         return Collections.emptyList();
180     }
181 
182     /**
183      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetPages()
184      */
185     protected List<FrontEndView> handleGetPages()
186     {
187         return this.getViews();
188     }
189 
190     /**
191      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetAllPages()
192      */
193     protected List<StrutsJsp> handleGetAllPages()
194     {
195         final List<StrutsJsp> pagesList = new ArrayList<StrutsJsp>();
196         for (final ActionStateFacade actionState : getModel().getAllActionStates())
197         {
198             if (actionState instanceof StrutsJsp)
199                 pagesList.add((StrutsJsp)actionState);
200         }
201         return pagesList;
202     }
203 
204     /**
205      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetFormFields()
206      */
207     protected List handleGetFormFields()
208     {
209         final List formFields = new ArrayList(); // parameter names are supposed to be unique
210 
211         for (final StrutsJsp jsp : getPages())
212         {
213             for (final StrutsParameter parameter : jsp.getPageVariables())
214             {
215                 formFields.add(parameter);
216             }
217             for (final FrontEndParameter parameter : jsp.getAllActionParameters())
218             {
219                 formFields.add(parameter);
220             }
221         }
222         return formFields;
223     }
224 
225     /**
226      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsValidationRequired()
227      */
228     protected boolean handleIsValidationRequired()
229     {
230         for (final StrutsJsp jsp : this.getAllPages())
231         {
232             if (jsp.isValidationRequired())
233             {
234                 return true;
235             }
236         }
237         return false;
238     }
239 
240     /**
241      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsApplicationValidationRequired()
242      */
243     protected boolean handleIsApplicationValidationRequired()
244     {
245         for (final FrontEndUseCase useCase : this.getAllUseCases())
246         {
247             if (((StrutsUseCase)useCase).isValidationRequired())
248             {
249                 return true;
250             }
251         }
252         return false;
253     }
254 
255     /**
256      * Overridden because StrutsAction does not extend FrontEndAction.
257      *
258      * @see org.andromda.metafacades.uml.FrontEndUseCase#getActions()
259      */
260     public List getActions()
261     {
262         final Collection actions = new LinkedHashSet();
263 
264         for (final StrutsJsp jsp : getPages())
265         {
266             actions.addAll(jsp.getActions());
267         }
268 
269         final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph();
270         if (graph != null)
271         {
272             final StrutsAction action = graph.getFirstAction();
273             if (action != null) actions.add(action);
274         }
275 
276         return new ArrayList(actions);
277     }
278 
279     /**
280      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetPageVariables()
281      */
282     protected List<FrontEndParameter>  handleGetPageVariables()
283     {
284         return this.getViewVariables();
285     }
286 
287     /**
288      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleIsApplicationUseCase()
289      */
290     protected boolean handleIsApplicationUseCase()
291     {
292         return this.isEntryUseCase();
293     }
294 
295     /**
296      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetCssFileName()
297      */
298     protected String handleGetCssFileName()
299     {
300         return this.getPackagePath() + '/' + Bpm4StrutsUtils.toWebFileName(this.getName()) + ".css";
301     }
302 
303     /**
304      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetApplicationHierarchyRoot()
305      */
306     protected TreeNode handleGetApplicationHierarchyRoot()
307     {
308         final UseCaseNode root = new UseCaseNode(this);
309         this.createHierarchy(root);
310         return root;
311     }
312 
313     /**
314      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetHierarchyRoot()
315      */
316     protected TreeNode handleGetHierarchyRoot()
317     {
318         UseCaseNode hierarchy = null;
319 
320         final Collection<FrontEndUseCase> allUseCases = this.getAllUseCases();
321         for (final Iterator<FrontEndUseCase> useCaseIterator = allUseCases.iterator(); useCaseIterator.hasNext();)
322         {
323             final StrutsUseCase useCase = (StrutsUseCase)useCaseIterator.next();
324             if (useCase.isApplicationUseCase())
325             {
326                 final UseCaseNode root = (UseCaseNode)useCase.getApplicationHierarchyRoot();
327                 hierarchy = this.findNode(root, this);
328             }
329         }
330         return hierarchy;
331     }
332 
333     /**
334      * Recursively creates a hierarchy of use-cases, starting with the argument use-case as the root. This is primarily
335      * meant to build a set of menu items.
336      */
337     private void createHierarchy(UseCaseNode root)
338     {
339         final StrutsUseCase useCase = (StrutsUseCase)root.getUserObject();
340 
341         final FrontEndActivityGraph graph = useCase.getActivityGraph();
342         if (graph != null)
343         {
344             final Collection<FinalStateFacade> finalStates = graph.getFinalStates();
345             for (final Iterator<FinalStateFacade> finalStateIterator = finalStates.iterator(); finalStateIterator.hasNext();)
346             {
347                 final StrutsFinalState finalState = (StrutsFinalState)finalStateIterator.next();
348                 final StrutsUseCase targetUseCase = (StrutsUseCase)finalState.getTargetUseCase();
349                 if (targetUseCase != null)
350                 {
351                     final UseCaseNode useCaseNode = new UseCaseNode(targetUseCase);
352                     if (!isNodeAncestor(root, useCaseNode))
353                     {
354                         root.add(useCaseNode);
355                         createHierarchy(useCaseNode);
356                     }
357                 }
358             }
359         }
360     }
361 
362     /**
363      * <code>true</code> if the argument ancestor node is actually an ancestor of the first node.
364      * <p>
365      * <em>Note: DefaultMutableTreeNode's isNodeAncestor does not work because of its specific impl.</em>
366      */
367     private boolean isNodeAncestor(
368         UseCaseNode node,
369         UseCaseNode ancestorNode)
370     {
371         boolean ancestor = false;
372 
373         if (node.getUseCase().equals(ancestorNode.getUseCase()))
374         {
375             ancestor = true;
376         }
377         while (!ancestor && node.getParent() != null)
378         {
379             node = (UseCaseNode)node.getParent();
380             if (this.isNodeAncestor(node, ancestorNode))
381             {
382                 ancestor = true;
383             }
384         }
385         return ancestor;
386     }
387 
388     /**
389      * Given a root use-case, finds the node in the hierarchy that represent the argument StrutsUseCase node.
390      */
391     private UseCaseNode findNode(
392         UseCaseNode root,
393         StrutsUseCase useCase)
394     {
395         UseCaseNode useCaseNode = null;
396 
397         final List<UseCaseNode> nodeList = Collections.list(root.breadthFirstEnumeration());
398         for (final Iterator<UseCaseNode> nodeIterator = nodeList.iterator(); nodeIterator.hasNext() && useCaseNode == null;)
399         {
400             UseCaseNode node = nodeIterator.next();
401             if (useCase.equals(node.getUserObject()))
402             {
403                 useCaseNode = node;
404             }
405         }
406         return useCaseNode;
407     }
408 
409     /**
410      *
411      */
412     public static final class UseCaseNode
413         extends DefaultMutableTreeNode
414     {
415         /**
416          * Automatically generated variable: serialVersionUID
417          */
418         private static final long serialVersionUID = -4839356733341754931L;
419 
420         /**
421          * @param useCase
422          */
423         public UseCaseNode(StrutsUseCase useCase)
424         {
425             super(useCase);
426         }
427 
428         /**
429          * @return getUserObject()
430          */
431         public StrutsUseCase getUseCase()
432         {
433             return (StrutsUseCase)getUserObject();
434         }
435     }
436 
437     private boolean normalizeMessages()
438     {
439         final String normalizeMessages = (String)getConfiguredProperty(Bpm4StrutsGlobals.PROPERTY_NORMALIZE_MESSAGES);
440         return Boolean.valueOf(normalizeMessages).booleanValue();
441     }
442 
443     /**
444      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetAllMessages()
445      */
446     protected Map handleGetAllMessages()
447     {
448         final boolean normalize = this.normalizeMessages();
449         final Map<String, String> messages = (normalize) ? new TreeMap() : new LinkedHashMap<String, String>();
450 
451         if (this.isApplicationUseCase())
452         {
453             final List<FrontEndUseCase> useCases = this.getAllUseCases();
454             for (int i = 0; i < useCases.size(); i++)
455             {
456                 // USECASE
457                 final StrutsUseCase useCase = (StrutsUseCase)useCases.get(i);
458                 messages.put(useCase.getTitleKey(), useCase.getTitleValue());
459                 messages.put(useCase.getOnlineHelpKey(), useCase.getOnlineHelpValue());
460 
461                 final List actions = useCase.getActions();
462                 for (int j = 0; j < actions.size(); j++)
463                 {
464                     final StrutsAction action = (StrutsAction)actions.get(j);
465 
466                     // FORWARDS
467                     for (StrutsForward forward : action.getTransitions())
468                     {
469                         messages.putAll(forward.getSuccessMessages());
470                         messages.putAll(forward.getWarningMessages());
471                     }
472 
473                     // EXCEPTION FORWARDS
474                     final List<StrutsExceptionHandler> exceptions = action.getActionExceptions();
475 
476                     if (normalize)
477                     {
478                         if (exceptions.isEmpty())
479                         {
480                             if (!action.isUseCaseStart())
481                             {
482                                 messages.put(action.getMessageKey() + ".exception", "{0} (java.lang.Exception)");
483                             }
484                         }
485                         else
486                         {
487                             for (final StrutsExceptionHandler exception : exceptions)
488                             {
489                                 messages.put(action.getMessageKey() + '.' + exception.getExceptionKey(), "{0}");
490                             }
491                         }
492                     }
493                     else
494                     {
495                         if (exceptions.isEmpty())
496                         {
497                             if (!action.isUseCaseStart())
498                             {
499                                 messages.put(action.getMessageKey() + ".exception", "{0} (java.lang.Exception)");
500                             }
501                         }
502                         else
503                         {
504                             for (int l = 0; l < exceptions.size(); l++)
505                             {
506                                 final StrutsExceptionHandler exception = exceptions.get(l);
507                                 // we construct the key using the action message too because the exception can
508                                 // belong to more than one action (therefore it cannot return the correct value
509                                 // in .getExceptionKey())
510                                 messages.put(action.getMessageKey() + '.' + exception.getExceptionKey(),
511                                     "{0} (" + exception.getExceptionType() + ')');
512                             }
513                         }
514                     }
515 
516                     // TRIGGER
517                     final StrutsTrigger trigger = action.getActionTrigger();
518                     if (trigger != null)
519                     {
520                         // only add these when a trigger is present, otherwise it's no use having them
521                         messages.put(action.getOnlineHelpKey(), action.getOnlineHelpValue());
522                         messages.put(action.getDocumentationKey(), action.getDocumentationValue());
523 
524                         // the regular trigger messages
525                         messages.put(trigger.getTitleKey(), trigger.getTitleValue());
526                         messages.put(trigger.getNotAllowedTitleKey(), trigger.getNotAllowedTitleValue());
527                         messages.put(trigger.getResetMessageKey(), trigger.getResetMessageValue());
528                         messages.put(trigger.getResetNotAllowedTitleKey(), trigger.getResetNotAllowedTitleValue());
529                         messages.put(trigger.getResetTitleKey(), trigger.getResetTitleValue());
530                         // this one is the same as doing: action.getMessageKey()
531                         messages.put(trigger.getTriggerKey(), trigger.getTriggerValue());
532 
533                         // IMAGE LINK
534                         if (action.isImageLink())
535                         {
536                             messages.put(action.getImageMessageKey(), action.getImagePath());
537                         }
538                     }
539                 }
540 
541                 final List pages = useCase.getPages();
542                 for (int j = 0; j < pages.size(); j++)
543                 {
544                     // PAGE
545                     final StrutsJsp page = (StrutsJsp)pages.get(j);
546                     messages.put(page.getTitleKey(), page.getTitleValue());
547                     messages.put(page.getMessageKey(), page.getMessageValue());
548                     messages.put(page.getOnlineHelpKey(), page.getOnlineHelpValue());
549                     messages.put(page.getDocumentationKey(), page.getDocumentationValue());
550 
551                     final List<StrutsParameter> pageVariables = page.getPageVariables();
552                     for (int k = 0; k < pageVariables.size(); k++)
553                     {
554                         // PAGE-VARIABLE
555                         final StrutsParameter parameter = pageVariables.get(k);
556 
557                         messages.put(parameter.getMessageKey(), parameter.getMessageValue());
558 /*
559                         if (normalize)
560                         {
561                             // the next line is in comment because it's not actually being used
562                             //messages.put(parameter.getTitleKey(), parameter.getTitleValue());
563                             messages.put(parameter.getMessageKey(), parameter.getMessageValue());
564                         }
565                         else
566                         {
567                             // the next line is in comment because it's not actually being used
568                             //messages.put(page.getTitleKey() + '.' + parameter.getTitleKey(), parameter.getTitleValue());
569                             messages.put(page.getTitleKey() + '.' + parameter.getMessageKey(),
570                                     parameter.getMessageValue());
571                         }
572 */
573 
574                         // TABLE
575                         if (parameter.isTable())
576                         {
577                             final Collection<String> columnNames = parameter.getTableColumnNames();
578                             for (final Iterator columnNameIterator = columnNames.iterator();
579                                  columnNameIterator.hasNext();)
580                             {
581                                 final String columnName = (String)columnNameIterator.next();
582                                 messages.put(parameter.getTableColumnMessageKey(columnName),
583                                     parameter.getTableColumnMessageValue(columnName));
584                             }
585                         }
586                     }
587 
588                     for (int k = 0; k < actions.size(); k++)
589                     {
590                         // ACTION
591                         final StrutsAction action = (StrutsAction)actions.get(k);
592 
593                         // ACTION PARAMETERS
594                         final List parameters = action.getActionParameters();
595                         for (int l = 0; l < parameters.size(); l++)
596                         {
597                             final StrutsParameter parameter = (StrutsParameter)parameters.get(l);
598                             messages.put(parameter.getMessageKey(), parameter.getMessageValue());
599                             messages.put(parameter.getOnlineHelpKey(), parameter.getOnlineHelpValue());
600                             messages.put(parameter.getDocumentationKey(), parameter.getDocumentationValue());
601                             messages.put(parameter.getTitleKey(), parameter.getTitleValue());
602 
603                             if (parameter.getValidWhen() != null)
604                             {
605                                 // this key needs to be fully qualified since the valid when value can be different
606                                 final String completeKeyPrefix = (normalize)
607                                     ? parameter.getMessageKey()
608                                     : useCase.getTitleKey() + '.' +
609                                     page.getMessageKey() + '.' +
610                                     action.getMessageKey() + '.' +
611                                     parameter.getMessageKey();
612                                 messages.put(completeKeyPrefix + "_validwhen",
613                                     "{0} is only valid when " + parameter.getValidWhen());
614                             }
615 
616                             if (parameter.getOptionCount() > 0)
617                             {
618                                 final List optionKeys = parameter.getOptionKeys();
619                                 final List optionValues = parameter.getOptionValues();
620 
621                                 for (int m = 0; m < optionKeys.size(); m++)
622                                 {
623                                     messages.put((String)optionKeys.get(m), (String)optionValues.get(m));
624                                     messages.put((String)optionKeys.get(m) + ".title", (String)optionValues.get(m));
625                                 }
626                             }
627                         }
628                     }
629                 }
630             }
631         }
632 
633         return messages;
634     }
635 
636     /**
637      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpPagePath()
638      */
639     protected String handleGetOnlineHelpPagePath()
640     {
641         final StringBuilder buffer = new StringBuilder();
642 
643         if (StringUtils.isNotBlank(this.getPackagePath()))
644         {
645             buffer.append('/');
646             buffer.append(this.getPackagePath());
647         }
648         buffer.append('/');
649         buffer.append(StringUtilsHelper.separate(this.getName(), "-"));
650         buffer.append("_help");
651 
652         return buffer.toString();
653     }
654 
655     /**
656      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpActionPath()
657      */
658     protected String handleGetOnlineHelpActionPath()
659     {
660         final StringBuilder buffer = new StringBuilder();
661 
662         if (StringUtils.isNotBlank(this.getPackagePath()))
663         {
664             buffer.append('/');
665             buffer.append(this.getPackagePath());
666         }
667         buffer.append('/');
668         buffer.append(StringUtilsHelper.upperCamelCaseName(this.getName()));
669         buffer.append("Help");
670 
671         return buffer.toString();
672     }
673 
674     /**
675      * @return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_KEY
676      * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase#getFormKey()
677      */
678     protected String handleGetFormKey()
679     {
680         final Object formKeyValue = this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_KEY);
681         return formKeyValue == null
682             ? Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_DEFAULT_KEY
683             : String.valueOf(formKeyValue);
684     }
685 }