001package org.andromda.cartridges.bpm4struts.metafacades; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Collections; 006import java.util.Iterator; 007import java.util.LinkedHashMap; 008import java.util.LinkedHashSet; 009import java.util.List; 010import java.util.Map; 011import java.util.TreeMap; 012import javax.swing.tree.DefaultMutableTreeNode; 013import javax.swing.tree.TreeNode; 014import org.andromda.cartridges.bpm4struts.Bpm4StrutsGlobals; 015import org.andromda.cartridges.bpm4struts.Bpm4StrutsProfile; 016import org.andromda.cartridges.bpm4struts.Bpm4StrutsUtils; 017import org.andromda.metafacades.uml.ActionStateFacade; 018import org.andromda.metafacades.uml.ActivityGraphFacade; 019import org.andromda.metafacades.uml.FinalStateFacade; 020import org.andromda.metafacades.uml.FrontEndActivityGraph; 021import org.andromda.metafacades.uml.FrontEndParameter; 022import org.andromda.metafacades.uml.FrontEndUseCase; 023import org.andromda.metafacades.uml.FrontEndView; 024import org.andromda.metafacades.uml.Role; 025import org.andromda.utils.StringUtilsHelper; 026import org.apache.commons.lang.StringUtils; 027 028/** 029 * MetafacadeLogic implementation. 030 * 031 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCase 032 */ 033public class StrutsUseCaseLogicImpl 034 extends StrutsUseCaseLogic 035{ 036 private static final long serialVersionUID = 34L; 037 /** 038 * @param metaObject 039 * @param context 040 */ 041 public StrutsUseCaseLogicImpl( 042 Object metaObject, 043 String context) 044 { 045 super(metaObject, context); 046 } 047 048 /** 049 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleKey() 050 */ 051 protected String handleGetTitleKey() 052 { 053 return StringUtilsHelper.toResourceMessageKey(normalizeMessages() ? getTitleValue() : getName()) + ".title"; 054 } 055 056 /** 057 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetTitleValue() 058 */ 059 protected String handleGetTitleValue() 060 { 061 return StringUtilsHelper.toPhrase(getName()); 062 } 063 064 /** 065 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpKey() 066 */ 067 protected String handleGetOnlineHelpKey() 068 { 069 return StringUtilsHelper.toResourceMessageKey(getName()) + ".online.help"; 070 } 071 072 /** 073 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetOnlineHelpValue() 074 */ 075 protected String handleGetOnlineHelpValue() 076 { 077 final String crlf = "<br/>"; 078 final StringBuilder buffer = new StringBuilder(); 079 080 buffer.append(!this.isDocumentationPresent() ? "No use-case documentation has been specified" 081 : StringUtilsHelper.toResourceMessage(this.getDocumentation("", 64, false))); 082 buffer.append(crlf); 083 084 return StringUtilsHelper.toResourceMessage(buffer.toString()); 085 } 086 087 /** 088 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsUseCaseLogic#handleGetActionPath() 089 */ 090 protected String handleGetActionPath() 091 { 092 String actionPath = null; 093 094 final StrutsActivityGraph graph = (StrutsActivityGraph)getActivityGraph(); 095 if (graph != null) 096 { 097 final StrutsAction action = graph.getFirstAction(); 098 if (action != null) 099 { 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}