1 package org.andromda.cartridges.jsf.metafacades;
2
3 import java.security.MessageDigest;
4 import java.security.NoSuchAlgorithmException;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.Iterator;
9 import java.util.LinkedHashMap;
10 import java.util.List;
11 import java.util.Map;
12
13 import org.andromda.cartridges.jsf.JSFGlobals;
14 import org.andromda.cartridges.jsf.JSFProfile;
15 import org.andromda.cartridges.jsf.JSFUtils;
16 import org.andromda.metafacades.uml.ClassifierFacade;
17 import org.andromda.metafacades.uml.EventFacade;
18 import org.andromda.metafacades.uml.FrontEndAction;
19 import org.andromda.metafacades.uml.ModelElementFacade;
20 import org.andromda.metafacades.uml.UseCaseFacade;
21 import org.andromda.utils.StringUtilsHelper;
22 import org.apache.commons.collections.CollectionUtils;
23 import org.apache.commons.collections.Predicate;
24 import org.apache.commons.lang.ObjectUtils;
25 import org.apache.commons.lang.StringUtils;
26
27
28 /**
29 * MetafacadeLogic implementation for org.andromda.cartridges.jsf.metafacades.JSFAction.
30 *
31 * @see org.andromda.cartridges.jsf.metafacades.JSFAction
32 */
33 public class JSFActionLogicImpl
34 extends JSFActionLogic
35 {
36 public JSFActionLogicImpl(
37 Object metaObject,
38 String context)
39 {
40 super(metaObject, context);
41 }
42
43 /**
44 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormBeanName()
45 */
46 protected java.lang.String handleGetFormBeanName()
47 {
48 return this.getFormBeanName(true);
49 }
50
51 /**
52 * Constructs the form bean name, with our without prefixing the use case name.
53 *
54 * @param withUseCaseName whether or not to prefix the use case name.
55 * @return the constructed form bean name.
56 */
57 private String getFormBeanName(boolean withUseCaseName)
58 {
59 final String pattern = ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.FORM_BEAN_PATTERN));
60 final ModelElementFacade useCase = this.getUseCase();
61 final String useCaseName = withUseCaseName && useCase != null ? StringUtilsHelper.lowerCamelCaseName(useCase.getName()) : "";
62 final String formBeanName = pattern.replaceFirst("\\{0\\}", useCaseName);
63 final String triggerName = !pattern.equals(formBeanName) ? StringUtils.capitalize(this.getTriggerName()) : this.getTriggerName();
64 return formBeanName.replaceFirst(
65 "\\{1\\}",
66 triggerName);
67 }
68
69 /**
70 * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
71 */
72 public String getName()
73 {
74 return JSFUtils.toWebResourceName(this.getUseCase().getName() + "-" + super.getName());
75 }
76
77 /**
78 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getTriggerName()
79 */
80 protected String handleGetTriggerName()
81 {
82 String name = null;
83 if (this.isExitingInitialState())
84 {
85 final JSFUseCase useCase = (JSFUseCase)this.getUseCase();
86 if (useCase != null)
87 {
88 name = useCase.getName();
89 }
90 }
91 else
92 {
93 final EventFacade trigger = this.getTrigger();
94 final String suffix = trigger == null ? this.getTarget().getName() : trigger.getName();
95 name = this.getSource().getName() + ' ' + suffix;
96 }
97 return StringUtilsHelper.lowerCamelCaseName(name);
98 }
99
100 /**
101 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormImplementationName()
102 */
103 protected java.lang.String handleGetFormImplementationName()
104 {
105 final String pattern =
106 ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.FORM_IMPLEMENTATION_PATTERN));
107 return pattern.replaceFirst(
108 "\\{0\\}",
109 StringUtils.capitalize(this.getTriggerName()));
110 }
111
112 /**
113 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedFormImplementationName()
114 */
115 protected boolean handleIsTableAction()
116 {
117 return JSFGlobals.ACTION_TYPE_TABLE.equals(this.findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_TYPE));
118 }
119
120 /**
121 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedFormImplementationName()
122 */
123 protected java.lang.String handleGetFullyQualifiedFormImplementationName()
124 {
125 final StringBuffer fullyQualifiedName = new StringBuffer();
126 final String packageName = this.getPackageName();
127 if (StringUtils.isNotBlank(packageName))
128 {
129 fullyQualifiedName.append(packageName + '.');
130 }
131 return fullyQualifiedName.append(this.getFormImplementationName()).toString();
132 }
133
134 /**
135 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedFormImplementationPath()
136 */
137 protected java.lang.String handleGetFullyQualifiedFormImplementationPath()
138 {
139 return this.getFullyQualifiedFormImplementationName().replace(
140 '.',
141 '/');
142 }
143
144 /**
145 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedFormImplementationPath()
146 */
147 protected String handleGetFormScope()
148 {
149 String scope = ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_FORM_SCOPE));
150 if (StringUtils.isEmpty(scope))
151 {
152 scope = ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.FORM_SCOPE));
153 }
154 return scope;
155 }
156
157 /**
158 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormImplementationInterfaceList()
159 */
160 protected String handleGetFormImplementationInterfaceList()
161 {
162 final List deferredOperations = this.getDeferredOperations();
163 for (final Iterator iterator = deferredOperations.iterator(); iterator.hasNext();)
164 {
165
166 final JSFControllerOperation operation = (JSFControllerOperation)iterator.next();
167 if (operation.getArguments().isEmpty())
168 {
169 iterator.remove();
170 }
171 }
172 final StringBuffer list = new StringBuffer();
173 for (final Iterator iterator = deferredOperations.iterator(); iterator.hasNext();)
174 {
175 final JSFControllerOperation operation = (JSFControllerOperation)iterator.next();
176 list.append(operation.getFormName());
177 if (iterator.hasNext())
178 {
179 list.append(", ");
180 }
181 }
182 return list.toString();
183 }
184
185 /**
186 * @see org.andromda.cartridges.jsf.metafacades.JSFActionLogic#handleGetPath()
187 */
188 protected String handleGetPath()
189 {
190 String path = this.getPathRoot() + '/' + JSFUtils.toWebResourceName(this.getTriggerName());
191 if (this.isExitingInitialState())
192 {
193 final JSFUseCase useCase = (JSFUseCase)this.getUseCase();
194 if (useCase != null && useCase.isViewHasNameOfUseCase())
195 {
196
197
198
199 path = path + "uc";
200 }
201 }
202 return path;
203 }
204
205 /**
206 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getPathRoot()
207 */
208 protected String handleGetPathRoot()
209 {
210 final StringBuffer pathRoot = new StringBuffer();
211 final JSFUseCase useCase = (JSFUseCase)this.getUseCase();
212 if (useCase != null)
213 {
214 pathRoot.append(useCase.getPathRoot());
215 }
216 return pathRoot.toString();
217 }
218
219 /**
220 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getMessageKey()
221 */
222 protected String handleGetMessageKey()
223 {
224 String messageKey = null;
225
226 final Object trigger = this.getTrigger();
227 if (trigger instanceof JSFEvent)
228 {
229 final JSFEvent actionTrigger = (JSFEvent)trigger;
230 if (actionTrigger != null)
231 {
232 messageKey = actionTrigger.getMessageKey();
233 }
234 }
235 return messageKey;
236 }
237
238 /**
239 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getDocumentationKey()
240 */
241 protected String handleGetDocumentationKey()
242 {
243 final Object trigger = this.getTrigger();
244 JSFEvent event = null;
245 if (trigger instanceof JSFEvent)
246 {
247 event = (JSFEvent)trigger;
248 }
249 return (event == null ? this.getMessageKey() + ".is.an.action.without.trigger" : event.getMessageKey()) +
250 '.' + JSFGlobals.DOCUMENTATION_MESSAGE_KEY_SUFFIX;
251 }
252
253 /**
254 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getDocumentationValue()
255 */
256 protected String handleGetDocumentationValue()
257 {
258 final String value = StringUtilsHelper.toResourceMessage(getDocumentation(
259 "",
260 64,
261 false));
262 return value == null ? "" : value;
263 }
264
265 /**
266 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getViewFragmentPath()
267 */
268 protected String handleGetViewFragmentPath()
269 {
270 return '/' + this.getPackageName().replace(
271 '.',
272 '/') + '/' + JSFUtils.toWebResourceName(this.getTriggerName());
273 }
274
275 /**
276 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getTableLinkName()
277 */
278 protected String handleGetTableLinkName()
279 {
280 String tableLink = null;
281
282 final Object value = findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_TABLELINK);
283 if (value != null)
284 {
285 tableLink = StringUtils.trimToNull(value.toString());
286
287 if (tableLink != null)
288 {
289 final int columnOffset = tableLink.indexOf('.');
290 tableLink = columnOffset == -1 ? tableLink : tableLink.substring(
291 0,
292 columnOffset);
293 }
294 }
295
296 return tableLink;
297 }
298
299 /**
300 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getTableLinkColumnName()
301 */
302 protected String handleGetTableLinkColumnName()
303 {
304 String tableLink = null;
305 final Object value = findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_TABLELINK);
306 if (value != null)
307 {
308 tableLink = StringUtils.trimToNull(value.toString());
309
310 if (tableLink != null)
311 {
312 final int columnOffset = tableLink.indexOf('.');
313 tableLink =
314 (columnOffset == -1 || columnOffset == tableLink.length() - 1) ? null
315 : tableLink.substring(
316 columnOffset + 1);
317 }
318 }
319 return tableLink;
320 }
321
322 /**
323 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isTableLink()
324 */
325 protected Object handleGetTableLinkParameter()
326 {
327 JSFParameter tableLinkParameter = null;
328 final String tableLinkName = this.getTableLinkName();
329 if (tableLinkName != null)
330 {
331 final JSFView view = (JSFView)this.getInput();
332 if (view != null)
333 {
334 final List tables = view.getTables();
335 for (int ctr = 0; ctr < tables.size() && tableLinkParameter == null; ctr++)
336 {
337 final Object object = tables.get(ctr);
338 if (object instanceof JSFParameter)
339 {
340 final JSFParameter table = (JSFParameter)object;
341 if (tableLinkName.equals(table.getName()))
342 {
343 tableLinkParameter = table;
344 }
345 }
346 }
347 }
348 }
349 return tableLinkParameter;
350 }
351
352 /**
353 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isTableLink()
354 */
355 protected boolean handleIsTableLink()
356 {
357 return this.getTableLinkParameter() != null;
358 }
359
360 /**
361 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isHyperlink()
362 */
363 protected boolean handleIsHyperlink()
364 {
365 final Object value = findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_TYPE);
366 return JSFGlobals.ACTION_TYPE_HYPERLINK.equalsIgnoreCase(value == null ? null : value.toString());
367 }
368
369 /**
370 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getActionClassName()
371 */
372 protected String handleGetActionClassName()
373 {
374 return StringUtilsHelper.upperCamelCaseName(this.getTriggerName());
375 }
376
377 /**
378 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedActionClassPath()
379 */
380 protected String handleGetFullyQualifiedActionClassPath()
381 {
382 return this.getFullyQualifiedActionClassName().replace(
383 '.',
384 '/') + ".java";
385 }
386
387 /**
388 * Overriddent to provide the owning use case's package name.
389 *
390 * @see org.andromda.metafacades.uml.ModelElementFacade#getPackageName()
391 */
392 public String getPackageName()
393 {
394 final UseCaseFacade useCase = this.getUseCase();
395 return useCase != null ? useCase.getPackageName() : "";
396 }
397
398 /**
399 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getControllerAction()
400 */
401 protected String handleGetControllerAction()
402 {
403 return this.getTriggerName();
404 }
405
406 /**
407 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFullyQualifiedActionClassName()
408 */
409 protected String handleGetFullyQualifiedActionClassName()
410 {
411 final StringBuffer path = new StringBuffer();
412 final JSFUseCase useCase = (JSFUseCase)this.getUseCase();
413 if (useCase != null)
414 {
415 final String packageName = useCase.getPackageName();
416 if (StringUtils.isNotBlank(packageName))
417 {
418 path.append(packageName);
419 path.append('.');
420 }
421 }
422 path.append(this.getActionClassName());
423 return path.toString();
424 }
425
426 /**
427 * @see org.andromda.cartridges.struts.metafacades.JSFAction#isResettable()
428 */
429 protected boolean handleIsResettable()
430 {
431 final Object value = findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_RESETTABLE);
432 return this.isTrue(value == null ? null : value.toString());
433 }
434
435 /**
436 * Convenient method to detect whether or not a String instance represents a boolean <code>true</code> value.
437 */
438 private boolean isTrue(String string)
439 {
440 return "yes".equalsIgnoreCase(string) || "true".equalsIgnoreCase(string) || "on".equalsIgnoreCase(string) ||
441 "1".equalsIgnoreCase(string);
442 }
443
444 /**
445 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getOtherUseCaseFormActions()
446 */
447 protected List handleGetOtherUseCaseFormActions()
448 {
449 final List otherActions = new ArrayList(this.getUseCase().getActions());
450 for (final Iterator iterator = otherActions.iterator(); iterator.hasNext();)
451 {
452 final FrontEndAction action = (FrontEndAction)iterator.next();
453
454
455 if (action.equals(this.THIS()) || action.getFormFields().isEmpty())
456 {
457 iterator.remove();
458 }
459 }
460 return otherActions;
461 }
462
463 /**
464 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormKey()
465 */
466 protected String handleGetFormKey()
467 {
468 final Object formKeyValue = this.findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_FORM_KEY);
469 return formKeyValue == null ? ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.ACTION_FORM_KEY))
470 : String.valueOf(formKeyValue);
471 }
472
473 /**
474 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#handleGetHiddenParameters()
475 */
476 protected List handleGetHiddenParameters()
477 {
478 final List hiddenParameters = new ArrayList(this.getParameters());
479 CollectionUtils.filter(
480 hiddenParameters,
481 new Predicate()
482 {
483 public boolean evaluate(final Object object)
484 {
485 boolean valid = false;
486 if (object instanceof JSFParameter)
487 {
488 final JSFParameter parameter = (JSFParameter)object;
489 valid = parameter.isInputHidden();
490 if (!valid)
491 {
492 for (final Iterator iterator = parameter.getAttributes().iterator(); iterator.hasNext();)
493 {
494 JSFAttribute attribute = (JSFAttribute)iterator.next();
495 valid = attribute.isInputHidden();
496 if (valid)
497 {
498 break;
499 }
500 }
501 }
502 }
503 return valid;
504 }
505 });
506 return hiddenParameters;
507 }
508
509 /**
510 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#handleGetHiddenParameters()
511 */
512 protected boolean handleIsValidationRequired()
513 {
514 boolean required = false;
515 final Collection actionParameters = this.getParameters();
516 for (final Iterator iterator = actionParameters.iterator(); iterator.hasNext();)
517 {
518 final Object object = iterator.next();
519 if (object instanceof JSFParameter)
520 {
521 final JSFParameter parameter = (JSFParameter)object;
522 if (parameter.isValidationRequired())
523 {
524 required = true;
525 break;
526 }
527 }
528 }
529 return required;
530 }
531
532 /**
533 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isPopup()
534 */
535 protected boolean handleIsPopup()
536 {
537 boolean popup = ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_TYPE)).equalsIgnoreCase(
538 JSFGlobals.VIEW_TYPE_POPUP);
539 if (!popup)
540 {
541 for (final Iterator iterator = this.getTargetViews().iterator(); iterator.hasNext();)
542 {
543 final JSFView view = (JSFView)iterator.next();
544 popup = view.isPopup();
545 if (!popup)
546 {
547 break;
548 }
549 }
550 }
551 return popup;
552 }
553
554 /**
555 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isFormResetRequired()
556 */
557 protected boolean handleIsFormResetRequired()
558 {
559 boolean resetRequired = this.isFormReset();
560 if (!resetRequired)
561 {
562 for (final Iterator iterator = this.getParameters().iterator(); iterator.hasNext();)
563 {
564 final Object object = iterator.next();
565 if (object instanceof JSFParameter)
566 {
567 final JSFParameter parameter = (JSFParameter)object;
568 resetRequired = parameter.isReset();
569 if (resetRequired)
570 {
571 break;
572 }
573 else if (parameter.isComplex())
574 {
575 final ClassifierFacade type = parameter.getType();
576 final Collection attributes = type.getAttributes(true);
577 for (final Iterator attributeIterator = attributes.iterator(); attributeIterator.hasNext();)
578 {
579 final Object attribute = attributeIterator.next();
580 if (attribute instanceof JSFAttribute)
581 {
582 final JSFAttribute jsfAttribute = (JSFAttribute)attribute;
583 if (jsfAttribute.isReset())
584 {
585 resetRequired = true;
586 break;
587 }
588 }
589 }
590 }
591 }
592 }
593 }
594 return resetRequired;
595 }
596
597 /**
598 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormSerialVersionUID()
599 */
600 protected String handleGetFormSerialVersionUID()
601 {
602 final StringBuffer buffer = new StringBuffer();
603
604 buffer.append(this.getName());
605
606 final ModelElementFacade input = this.getInput();
607 buffer.append(input != null ? input.getName() : "");
608
609 final ModelElementFacade guard = this.getGuard();
610 buffer.append(guard != null ? guard.getName() : "");
611
612 final ModelElementFacade effect = this.getEffect();
613 buffer.append(effect != null ? effect.getName() : "");
614
615 final ModelElementFacade decisionsTrigger = this.getDecisionTrigger();
616 buffer.append(decisionsTrigger != null ? decisionsTrigger.getName() : "");
617
618 buffer.append(StringUtils.trimToEmpty(this.getActionClassName()));
619
620 for (final Iterator iterator = this.getParameters().iterator(); iterator.hasNext();)
621 {
622 final ModelElementFacade parameter = (ModelElementFacade)iterator.next();
623 buffer.append(parameter.getName());
624 }
625
626 for (final Iterator iterator = this.getActionForwards().iterator(); iterator.hasNext();)
627 {
628 final ModelElementFacade forward = (ModelElementFacade)iterator.next();
629 buffer.append(forward.getName());
630 }
631
632 for (final Iterator iterator = this.getActions().iterator(); iterator.hasNext();)
633 {
634 final ModelElementFacade action = (ModelElementFacade)iterator.next();
635 buffer.append(action.getName());
636 }
637
638 for (final Iterator iterator = this.getActionStates().iterator(); iterator.hasNext();)
639 {
640 final ModelElementFacade state = (ModelElementFacade)iterator.next();
641 buffer.append(state.getName());
642 }
643 final String signature = buffer.toString();
644
645 String serialVersionUID = String.valueOf(0L);
646 try
647 {
648 MessageDigest md = MessageDigest.getInstance("SHA");
649 byte[] hashBytes = md.digest(signature.getBytes());
650
651 long hash = 0;
652 for (int ctr = Math.min(
653 hashBytes.length,
654 8) - 1; ctr >= 0; ctr--)
655 {
656 hash = (hash << 8) | (hashBytes[ctr] & 0xFF);
657 }
658 serialVersionUID = String.valueOf(hash);
659 }
660 catch (final NoSuchAlgorithmException exception)
661 {
662 final String message = "Error performing JSFAction.getFormSerialVersionUID";
663 logger.error(
664 message,
665 exception);
666 }
667 return serialVersionUID;
668 }
669
670 /**
671 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isFormRequired()
672 */
673 protected boolean handleIsFormReset()
674 {
675 return Boolean.valueOf(ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_ACTION_FORM_RESET))).booleanValue();
676 }
677
678 /**
679 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFormImplementationGetter()
680 */
681 protected String handleGetFormImplementationGetter()
682 {
683 return "get" + StringUtils.capitalize(this.getFormBeanName(false)) + "()";
684 }
685
686 /**
687 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#isFinalStateTarget()
688 */
689 protected boolean handleIsFinalStateTarget()
690 {
691 return this.getTarget() instanceof JSFFinalState;
692 }
693
694 /**
695 * @see org.andromda.cartridges.jsf.metafacades.JSFAction#getFromOutcome()
696 */
697 protected String handleGetFromOutcome()
698 {
699 return this.getName();
700 }
701
702 protected boolean handleIsSuccessMessagesPresent()
703 {
704 return !this.getSuccessMessages().isEmpty();
705 }
706
707 protected boolean handleIsWarningMessagesPresent()
708 {
709 return !this.getWarningMessages().isEmpty();
710 }
711
712 /**
713 * Collects specific messages in a map.
714 *
715 * @param taggedValue the tagged value from which to read the message
716 * @return maps message keys to message values, but only those that match the arguments
717 * will have been recorded
718 */
719 private Map getMessages(String taggedValue)
720 {
721 Map messages;
722
723 final Collection taggedValues = this.findTaggedValues(taggedValue);
724 if (taggedValues.isEmpty())
725 {
726 messages = Collections.EMPTY_MAP;
727 }
728 else
729 {
730 messages = new LinkedHashMap();
731
732 for (final Iterator iterator = taggedValues.iterator(); iterator.hasNext();)
733 {
734 final String value = (String)iterator.next();
735 messages.put(StringUtilsHelper.toResourceMessageKey(value), value);
736 }
737 }
738
739 return messages;
740 }
741
742 protected Map handleGetSuccessMessages()
743 {
744 return this.getMessages(JSFProfile.TAGGEDVALUE_ACTION_SUCCESS_MESSAGE);
745 }
746
747 protected Map handleGetWarningMessages()
748 {
749 return this.getMessages(JSFProfile.TAGGEDVALUE_ACTION_WARNING_MESSAGE);
750 }
751 }