001package org.andromda.cartridges.webservice.metafacades; 002 003import java.text.Collator; 004import java.text.MessageFormat; 005import java.util.ArrayList; 006import java.util.Collection; 007import java.util.Collections; 008import java.util.Comparator; 009import java.util.HashMap; 010import java.util.HashSet; 011import java.util.Iterator; 012import java.util.LinkedHashSet; 013import java.util.List; 014import java.util.Map; 015import java.util.Set; 016import java.util.TreeMap; 017import java.util.TreeSet; 018import org.andromda.cartridges.webservice.WebServiceGlobals; 019import org.andromda.cartridges.webservice.WebServiceUtils; 020import org.andromda.core.common.ExceptionUtils; 021import org.andromda.core.common.Introspector; 022import org.andromda.core.metafacade.MetafacadeBase; 023import org.andromda.core.metafacade.MetafacadeException; 024import org.andromda.core.metafacade.ModelValidationMessage; 025import org.andromda.metafacades.uml.AssociationEndFacade; 026import org.andromda.metafacades.uml.AttributeFacade; 027import org.andromda.metafacades.uml.ClassifierFacade; 028import org.andromda.metafacades.uml.GeneralizableElementFacade; 029import org.andromda.metafacades.uml.ModelElementFacade; 030import org.andromda.metafacades.uml.OperationFacade; 031import org.andromda.metafacades.uml.PackageFacade; 032import org.andromda.metafacades.uml.ParameterFacade; 033import org.andromda.metafacades.uml.Role; 034import org.andromda.metafacades.uml.ServiceOperation; 035import org.andromda.metafacades.uml.TypeMappings; 036import org.andromda.metafacades.uml.UMLMetafacadeProperties; 037import org.andromda.metafacades.uml.UMLProfile; 038import org.andromda.translation.ocl.validation.OCLExpressions; 039import org.andromda.translation.ocl.validation.OCLIntrospector; 040import org.apache.commons.collections.Closure; 041import org.apache.commons.collections.CollectionUtils; 042import org.apache.commons.collections.Predicate; 043import org.apache.commons.lang.ObjectUtils; 044import org.apache.commons.lang.StringUtils; 045import org.apache.log4j.Logger; 046 047/** 048 * MetafacadeLogic implementation for org.andromda.cartridges.webservice.metafacades.WebService. 049 * 050 * @see org.andromda.cartridges.webservice.metafacades.WebService 051 * @author Bob Fields 052 */ 053public class WebServiceLogicImpl 054 extends WebServiceLogic 055{ 056 private static final long serialVersionUID = 34L; 057 // ---------------- constructor ------------------------------- 058 /** 059 * @param metaObject 060 * @param context 061 */ 062 public WebServiceLogicImpl( 063 Object metaObject, 064 String context) 065 { 066 super(metaObject, context); 067 } 068 069 /** 070 * The logger instance. 071 */ 072 private static final Logger logger = Logger.getLogger(WebServiceLogicImpl.class); 073 074 private static final String DEFAULT = "default"; 075 076 /** 077 * @return operations filtered by ((WebServiceOperation)object).isExposed() 078 * @see org.andromda.cartridges.webservice.metafacades.WebService#getAllowedOperations() 079 */ 080 protected Collection<OperationFacade> handleGetAllowedOperations() 081 { 082 List<OperationFacade> operations = new ArrayList<OperationFacade>(this.getOperations()); 083 CollectionUtils.filter( 084 operations, 085 new Predicate() 086 { 087 public boolean evaluate(Object object) 088 { 089 boolean valid = WebServiceOperation.class.isAssignableFrom(object.getClass()); 090 if (valid) 091 { 092 valid = ((WebServiceOperation)object).isExposed(); 093 } 094 return valid; 095 } 096 }); 097 if (this.getWSDLOperationSortMode().equals(OPERATION_SORT_MODE_NAME)) 098 { 099 Collections.sort( 100 operations, 101 new OperationNameComparator()); 102 } 103 return operations; 104 } 105 106 /** 107 * @return this.getAllowedOperations() separated by " " 108 * @see org.andromda.cartridges.webservice.metafacades.WebService#getAllowedMethods() 109 */ 110 protected String handleGetAllowedMethods() 111 { 112 Collection<String> methodNames = new ArrayList<String>(); 113 Collection<WebServiceOperation> operations = this.getAllowedOperations(); 114 if (operations != null && !operations.isEmpty()) 115 { 116 for (WebServiceOperation operation : operations) 117 { 118 methodNames.add(StringUtils.trimToEmpty(operation.getName())); 119 } 120 } 121 return StringUtils.join( 122 methodNames.iterator(), 123 " "); 124 } 125 126 /** 127 * @return this.getName() formatted as this.getQualifiedNameLocalPartPattern() 128 * @see org.andromda.cartridges.webservice.metafacades.WebService#getQName() 129 */ 130 protected String handleGetQName() 131 { 132 return MessageFormat.format( 133 this.getQualifiedNameLocalPartPattern(), 134 StringUtils.trimToEmpty(this.getName())); 135 } 136 137 /** 138 * @return this.getPackageName() reversed if this.isReverseNamespace() 139 * @see org.andromda.cartridges.webservice.metafacades.WebService#getNamespace() 140 */ 141 protected String handleGetNamespace() 142 { 143 String packageName = this.getPackageName(); 144 if (this.isReverseNamespace()) 145 { 146 packageName = WebServiceUtils.reversePackage(packageName); 147 } 148 return MessageFormat.format( 149 this.getNamespacePattern(), 150 StringUtils.trimToEmpty(packageName)); 151 } 152 153 /** 154 * The property defining the default style to give the web services. 155 */ 156 private static final String PROPERTY_DEFAULT_STYLE = "defaultStyle"; 157 158 /** 159 * @return UMLProfile.TAGGEDVALUE_WEBSERVICE_STYLE or this.getConfiguredProperty(PROPERTY_DEFAULT_STYLE) 160 * @see org.andromda.cartridges.webservice.metafacades.WebService#getStyle() 161 */ 162 protected String handleGetStyle() 163 { 164 String style = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_STYLE); 165 if (StringUtils.isBlank(style) || style.equals(DEFAULT)) 166 { 167 style = String.valueOf(this.getConfiguredProperty(PROPERTY_DEFAULT_STYLE)); 168 } 169 return style; 170 } 171 172 /** 173 * The property defining the default style to give the web services. 174 */ 175 private static final String PROPERTY_DEFAULT_USE = "defaultUse"; 176 177 /** 178 * @return UMLProfile.TAGGEDVALUE_WEBSERVICE_USE or this.getConfiguredProperty(PROPERTY_DEFAULT_USE 179 * @see org.andromda.cartridges.webservice.metafacades.WebService#getUse() 180 */ 181 protected String handleGetUse() 182 { 183 String use = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_USE); 184 if (StringUtils.isBlank(use) || use.equals(DEFAULT)) 185 { 186 use = String.valueOf(this.getConfiguredProperty(PROPERTY_DEFAULT_USE)); 187 } 188 return use; 189 } 190 191 /** 192 * Sorted list of all type mapping elements (package.class), used to iterate through all elements in a service 193 */ 194 private Set<ModelElementFacade> elementSet = new TreeSet<ModelElementFacade>(new TypeComparator()); 195 196 /** 197 * Keeps track of whether or not the type has been checked, keeps us from entering infinite loops when calling 198 * loadTypes. 199 */ 200 private Collection<ModelElementFacade> checkedTypes = new ArrayList<ModelElementFacade>(); 201 202 /** 203 * @return this.elementSet types 204 * @see org.andromda.cartridges.webservice.metafacades.WebService#getTypeMappingElements() 205 */ 206 protected Collection<ModelElementFacade> handleGetTypeMappingElements() 207 { 208 final Collection<ParameterFacade> parameterTypes = new LinkedHashSet<ParameterFacade>(); 209 for (final WebServiceOperation operation : this.getAllowedOperations()) 210 { 211 parameterTypes.addAll(operation.getParameters()); 212 } 213 214 final Set<ModelElementFacade> types = new TreeSet<ModelElementFacade>(new TypeComparator()); 215 final Collection<ModelElementFacade> nonArrayTypes = new TreeSet<ModelElementFacade>(new TypeComparator()); 216 217 // clear out the cache of checkedTypes, otherwise 218 // they'll be ignored the second time this method is 219 // called (if the instance is reused) 220 this.checkedTypes.clear(); 221 for (final ParameterFacade parameter : parameterTypes) 222 { 223 this.loadTypes((ModelElementFacade)parameter, types, nonArrayTypes); 224 } 225 226 for (final WebServiceOperation operation : this.getAllowedOperations()) 227 { 228 final Collection<ModelElementFacade> exceptions = operation.getExceptions(); 229 exceptions.addAll(exceptions); 230 // Exceptions may have attributes too 231 for (final ModelElementFacade exception : exceptions) 232 { 233 this.loadTypes(exception, types, nonArrayTypes); 234 } 235 } 236 237 // now since we're at the end, and we know the 238 // non array types won't override any other types 239 // (such as association ends) we 240 // add the non array types to the types 241 types.addAll(nonArrayTypes); 242 243 this.elementSet = types; 244 //setPkgAbbr(types); 245 return types; 246 } 247 248 /** 249 * <p> Loads all <code>types</code> and <code>nonArrayTypes</code> for 250 * the specified <code>type</code>. For each array type we collect the 251 * <code>nonArrayType</code>. Non array types are loaded separately so 252 * that they are added at the end at the type collecting process. Since the 253 * types collection is a set (by the fullyQualifiedName) we don't want any 254 * non array types to override things such as association ends in the 255 * <code>types</code> collection. 256 * </p> 257 * 258 * @param type the type 259 * @param types the collection to load. 260 * @param nonArrayTypes the collection of non array types. 261 */ 262 private void loadTypes(ModelElementFacade modelElement, Set<ModelElementFacade> types, 263 Collection<ModelElementFacade> nonArrayTypes) 264 { 265 ExceptionUtils.checkNull("types", types); 266 ExceptionUtils.checkNull("nonArrayTypes", nonArrayTypes); 267 268 try 269 { 270 if (modelElement != null && !this.checkedTypes.contains(modelElement)) 271 { 272 final ClassifierFacade parameterType = this.getType(modelElement); 273 274 // only continue if the model element has a type 275 if (parameterType != null) 276 { 277 final Set<ModelElementFacade> allTypes = new LinkedHashSet<ModelElementFacade>(); 278 allTypes.add(parameterType); 279 280 // add all generalizations and specializations of the type 281 final Collection<GeneralizableElementFacade> generalizations = parameterType.getAllGeneralizations(); 282 283 if (generalizations != null) 284 { 285 allTypes.addAll(generalizations); 286 } 287 288 final Collection<GeneralizableElementFacade> specializations = parameterType.getAllSpecializations(); 289 290 if (specializations != null) 291 { 292 allTypes.addAll(specializations); 293 } 294 295 if (!this.checkedTypes.contains(parameterType)) 296 { 297 this.checkedTypes.add(parameterType); 298 299 for (final Iterator allTypesIterator = allTypes.iterator(); allTypesIterator.hasNext();) 300 { 301 ClassifierFacade type = (ClassifierFacade) allTypesIterator.next(); 302 303 if (!this.containsManyType(types, modelElement)) 304 { 305 ClassifierFacade nonArrayType = type; 306 final boolean arrayType = type.isArrayType(); 307 308 if (arrayType || this.isValidAssociationEnd(modelElement)) 309 { 310 types.add(modelElement); 311 312 if (arrayType) 313 { 314 // convert to non-array type since we 315 // check if that one has the stereotype 316 nonArrayType = type.getNonArray(); 317 318 // set the type to the non array type since 319 // that will have the attributes 320 type = nonArrayType; 321 } 322 } 323 324 if (nonArrayType != null) 325 { 326 if (nonArrayType.hasStereotype(UMLProfile.STEREOTYPE_VALUE_OBJECT) 327 || nonArrayType.hasStereotype(UMLProfile.STEREOTYPE_APPLICATION_EXCEPTION) 328 || nonArrayType.isEnumeration()) 329 { 330 // we add the type when it's a non array and 331 // has the correct stereotype (even if we have 332 // added the array type above) since we need to 333 // define both an array and non array in the WSDL 334 // if we are defining an array. 335 nonArrayTypes.add(nonArrayType); 336 } 337 } 338 } 339 340 if (type != null) 341 { 342 final List<? extends ModelElementFacade> properties = type.getProperties(); 343 if (properties != null && !properties.isEmpty()) 344 { 345 for (final ModelElementFacade property : properties) 346 { 347 // Avoid StackOverflowError loading self-referenced types 348 if (!property.getFullyQualifiedName().equals(modelElement.getFullyQualifiedName())) 349 { 350 this.loadTypes(property, types, nonArrayTypes); 351 } 352 } 353 } 354 } 355 } 356 } 357 } 358 } 359 } 360 catch (final Throwable throwable) 361 { 362 final String message = "Error performing loadTypes"; 363 logger.error(throwable); 364 throw new MetafacadeException(message, throwable); 365 } 366 } 367 368 /** 369 * Cross reference between package name and namespace abbreviation, used to annotate foreign schema elements 370 */ 371 private Map<String, String> packageAbbr = new TreeMap<String, String>(); 372 private static final String EMPTY_STRING = ""; 373 374 /** 375 * Get a unique list of packages populated from the results of GetTypeMappingElements 376 * @return pkgAbbr TreeSet containing unique package list 377 */ 378 protected Collection<String> handleGetPackages() 379 { 380 if (this.elementSet == null || this.elementSet.size()<1) 381 { 382 this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements(); 383 } 384 setPkgAbbr(this.elementSet); 385 @SuppressWarnings("unused") 386 String pkgList = EMPTY_STRING; 387 for (final String pkg : this.packageAbbr.keySet()) 388 { 389 pkgList += pkg + ", "; 390 } 391 return this.packageAbbr.keySet(); 392 } 393 394 /** 395 * @param pkgName 396 * @return this.packageAbbr.get(pkgName) 397 */ 398 protected String handleGetPkgAbbr(String pkgName) 399 { 400 if (StringUtils.isBlank(pkgName) || pkgName.length()<1) 401 { 402 return EMPTY_STRING; 403 } 404 if (this.elementSet == null || this.elementSet.size()<1) 405 { 406 this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements(); 407 } 408 if (this.packageAbbr == null || this.packageAbbr.size()<1) 409 { 410 setPkgAbbr(this.elementSet); 411 } 412 String rtn = this.packageAbbr.get(pkgName); 413 if (StringUtils.isBlank(rtn)) 414 { 415 // Package reference was never added originally - needs to be fixed 416 int namespaceCount = this.packageAbbr.size(); 417 rtn = "ns" + namespaceCount; 418 this.packageAbbr.put(pkgName, rtn); 419 logger.info(this.getName() + " missing PkgAbbr for " + pkgName); 420 } 421 return rtn; 422 } 423 424 /** 425 * Creates a list of sorted unique package names and namespace abbreviations for each one. 426 * Run this after running getTypeMappingElements(), to populate the namespace Map. 427 * Namespaces are in order ns1 through x 428 * @param types 429 * @return pkgAbbr 430 */ 431 private Map<String, String> setPkgAbbr(Set<ModelElementFacade> types) 432 { 433 Map<String, String> pkgAbbr = new TreeMap<String, String>(); 434 int namespaceCount = 1; 435 // Copy package names and abbreviations to package list 436 for (final OperationFacade op : this.getOperations()) 437 { 438 for (final Iterator opiterator = op.getExceptions().iterator(); opiterator.hasNext();) 439 { 440 ModelElementFacade arg = (ModelElementFacade)opiterator.next(); 441 String pkg = arg.getPackageName(); 442 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0) 443 { 444 pkgAbbr.put(pkg, "ns" + namespaceCount); 445 namespaceCount++; 446 } 447 } 448 for (final ParameterFacade arg : op.getArguments()) 449 { 450 String pkg = arg.getPackageName(); 451 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0) 452 { 453 pkgAbbr.put(pkg, "ns" + namespaceCount); 454 namespaceCount++; 455 } 456 } 457 if (op.getReturnType()!=null) 458 { 459 String pkg = op.getReturnType().getPackageName(); 460 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0) 461 { 462 pkgAbbr.put(pkg, "ns" + namespaceCount); 463 namespaceCount++; 464 } 465 } 466 } 467 for (final Iterator iterator = types.iterator(); iterator.hasNext();) 468 { 469 ModelElementFacade type = ((ModelElementFacade)iterator.next()); 470 String pkg = type.getPackageName(); 471 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0) 472 { 473 pkgAbbr.put(pkg, "ns" + namespaceCount); 474 namespaceCount++; 475 } 476 } 477 this.packageAbbr = pkgAbbr; 478 return pkgAbbr; 479 } 480 481 /** 482 * Cross reference between package name and collection of foreign package referenced elements 483 */ 484 private Map<String, Set<String>> packageRefs = new HashMap<String, Set<String>>(); 485 486 /** 487 * Get a unique list of packages referenced by the referring package 488 * @param pkg PackageName to find related packages for xs:schema import 489 * @param follow Follow Inheritance references $extensionInheritanceDisabled 490 * @return Collection TreeSet containing referenced package list 491 */ 492 protected Collection<String> handleGetPackageReferences(String pkg, boolean follow) 493 { 494 //if (this.elementSet == null || this.elementSet.size()<1) 495 //{ 496 this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements(); 497 //} 498 //if (this.packageRefs == null || this.packageRefs.size()<1) 499 //{ 500 setPkgRefs(this.elementSet, follow); 501 //} 502 return this.packageRefs.get(pkg); 503 } 504 505 /** 506 * Creates a list of referenced packages for each package. 507 * Run this after running getTypeMappingElements(), to populate the namespace Map. 508 * @param types TreeSet of unique packageNames referenced in each package 509 * @param follow Follow Inheritance references $extensionInheritanceDisabled 510 * @return pkgAbbr 511 */ 512 private Map<String, Set<String>> setPkgRefs(Set<ModelElementFacade> types, boolean follow) 513 { 514 // Copy package names and collection of related packages to package references list 515 // Iterate through previously collected type references to find all packages referenced by each type 516 for (final Iterator<ModelElementFacade> iterator = types.iterator(); iterator.hasNext();) 517 { 518 try 519 { 520 MetafacadeBase element = (MetafacadeBase)iterator.next(); 521 if (element instanceof WSDLTypeLogicImpl) 522 { 523 WSDLTypeLogicImpl type = (WSDLTypeLogicImpl)element; 524 String pkg = type.getPackageName(); 525 if (pkg != null && pkg.indexOf('.') > 0) 526 { 527 // Duplicates logic in wsdl.vsl so that referenced packages are the same. 528 for (final Iterator<AttributeFacade> itAttr = type.getAttributes(follow).iterator(); itAttr.hasNext();) 529 { 530 try 531 { 532 ModelElementFacade attr = (itAttr.next()); 533 if (getType(attr) != null) 534 { 535 attr = getType(attr); 536 } 537 addPkgRef(pkg, attr.getPackageName(), attr); 538 } 539 catch (Exception e) 540 { 541 logger.error("WebServiceLogicImpl.setPkgRefs getAttributes: " + e); 542 } 543 } 544 } 545 } 546 else if (element instanceof WSDLTypeAssociationEndLogicImpl) 547 { 548 WSDLTypeAssociationEndLogicImpl type = (WSDLTypeAssociationEndLogicImpl)element; 549 String pkg = type.getPackageName(); 550 if (pkg != null && pkg.indexOf('.') > 0) 551 { 552 // Duplicates logic in wsdl.vsl so that referenced packages are the same. 553 for (final Iterator<AssociationEndFacade> otherEnds = type.getType().getNavigableConnectingEnds(follow).iterator(); otherEnds.hasNext();) 554 { 555 try 556 { 557 ModelElementFacade otherEnd = ((ModelElementFacade)otherEnds.next()); 558 if (getType(otherEnd) != null) 559 { 560 otherEnd = getType(otherEnd); 561 } 562 addPkgRef(pkg, otherEnd.getPackageName(), otherEnd); 563 } 564 catch (RuntimeException e) 565 { 566 logger.error("WebServiceLogicImpl.setPkgRefs getNavigableConnectingEnds: " + e); 567 } 568 } 569 } 570 } 571 else 572 { 573 // Log the type so we can extend this logic later... 574 logger.error("Unexpected element type: " + element); 575 } 576 } 577 catch (Exception e) 578 { 579 logger.error("WebServiceLogicImpl.setPkgRefs types: " + e); 580 } 581 } 582 // Copy package names and collection of related packages to package references list 583 /* for (final Iterator iterator = types.iterator(); iterator.hasNext();) 584 { 585 TreeSet pkgRef; 586 ClassifierFacade element = ((ClassifierFacade)iterator.next()); 587 String pkg = element.getPackageName(); 588 if (!packageRefs.containsKey(pkg)) 589 { 590 // TypeComparator disallows adding nonunique referenced packageNames 591 pkgRef = new TreeSet(new TypeComparator()); 592 } 593 else 594 { 595 // Reference to Set contained in pkgAbbr already, can be changed dynamically 596 pkgRef = (TreeSet)packageRefs.get(pkg); 597 } 598 // Duplicates logic in wsdl.vsl so that referenced packages are the same. 599 for (final Iterator itAttr = element.getAttributes(follow).iterator(); itAttr.hasNext();) 600 { 601 ClassifierFacade attr = ((ClassifierFacade)itAttr.next()); 602 if (getType(attr) != null) 603 { 604 attr = getType(attr); 605 } 606 if (!pkgRef.contains(attr) && attr != null && attr.getPackageName().length() > 0) 607 { 608 pkgRef.add(attr.getPackageName()); 609 } 610 } 611 for (final Iterator otherEnds = element.getNavigableConnectingEnds(follow).iterator(); otherEnds.hasNext();) 612 { 613 ClassifierFacade otherEnd = ((ClassifierFacade)otherEnds.next()); 614 if (getType(otherEnd) != null) 615 { 616 otherEnd = getType(otherEnd); 617 } 618 if (!pkgRef.contains(otherEnd)) 619 { 620 pkgRef.add(otherEnd.getPackageName()); 621 } 622 } 623 if (!packageRefs.containsKey(pkg)) 624 { 625 packageRefs.put(pkg, pkgRef); 626 } 627 } */ 628 629 // Add references from the operations of the service package itself 630 for (final OperationFacade op : this.getOperations()) 631 { 632 for (final Object exception : op.getExceptions()) 633 { 634 ModelElementFacade arg = (ModelElementFacade)exception; 635 addPkgRef(this.getPackageName(), arg.getPackageName(), arg); 636 } 637 for (final ParameterFacade arg : op.getArguments()) 638 { 639 addPkgRef(this.getPackageName(), arg.getPackageName(), arg); 640 } 641 if (op.getReturnType()!=null) 642 { 643 String pkg = op.getReturnType().getPackageName(); 644 addPkgRef(this.getPackageName(), pkg, op.getReturnType()); 645 } 646 } 647 return packageRefs; 648 } 649 650 private void addPkgRef(String pkg, String pkgRef, ModelElementFacade type) 651 { 652 Set<String> pkgRefSet; 653 if (!packageRefs.containsKey(pkg)) 654 { 655 // TypeComparator disallows adding nonunique referenced packageNames 656 pkgRefSet = new TreeSet<String>(); 657 packageRefs.put(pkg, pkgRefSet); 658 } 659 else 660 { 661 // Reference to Set contained in pkgAbbr already, can be changed dynamically 662 pkgRefSet = packageRefs.get(pkg); 663 } 664 if (pkgRef!=null && pkg!=null && !pkgRef.equals(pkg) && pkgRef.indexOf('.') > 0 && !pkgRefSet.contains(pkgRef)) 665 { 666 pkgRefSet.add(pkgRef); 667 logger.debug("Added pkgRef " + pkg + " references " + pkgRef + " in " + type.getName()); 668 } 669 } 670 671 /** 672 * <p> Checks to see if the <code>types</code> collection contains the 673 * <code>modelElement</code>. It does this by checking to see if the 674 * model element is either an association end or some type of model element 675 * that has a type that's an array. If it's either an array <strong>OR 676 * </strong> an association end, then we check to see if the type is stored 677 * within the <code>types</code> collection. If so, we return true, 678 * otherwise we return false. 679 * </p> 680 * 681 * @param types the previously collected types. 682 * @param modelElement the model element to check to see if it represents a 683 * <code>many</code> type 684 * @return true/false depending on whether or not the model element is a 685 * many type. 686 */ 687 private boolean containsManyType( 688 final Collection<ModelElementFacade> types, 689 final Object modelElement) 690 { 691 final ClassifierFacade compareType = this.getClassifier(modelElement); 692 boolean containsManyType = false; 693 if (compareType != null) 694 { 695 containsManyType = 696 CollectionUtils.find( 697 types, 698 new Predicate() 699 { 700 public boolean evaluate(Object object) 701 { 702 return compareType.equals(getClassifier(object)); 703 } 704 }) != null; 705 } 706 return containsManyType; 707 } 708 709 /** 710 * Attempts to get the classifier attached to the given <code>element</code>. 711 * 712 * @param element the element from which to retrieve the classifier. 713 * @return the classifier if found, null otherwise 714 */ 715 private ClassifierFacade getClassifier(final Object element) 716 { 717 ClassifierFacade type = null; 718 if (element instanceof AssociationEndFacade) 719 { 720 AssociationEndFacade end = (AssociationEndFacade)element; 721 if (end.isMany()) 722 { 723 type = ((AssociationEndFacade)element).getType(); 724 } 725 } 726 else if (element instanceof AttributeFacade) 727 { 728 type = ((AttributeFacade)element).getType(); 729 } 730 else if (element instanceof ParameterFacade) 731 { 732 type = ((ParameterFacade)element).getType(); 733 } 734 if (element instanceof ClassifierFacade) 735 { 736 type = (ClassifierFacade)element; 737 } 738 if (type != null) 739 { 740 if (type.isArrayType()) 741 { 742 type = type.getNonArray(); 743 } 744 } 745 return type; 746 } 747 748 /** 749 * Returns true/false depending on whether or not this class represents a valid association end (meaning it has a 750 * multiplicity of many) 751 * 752 * @param modelElement the model element to check. 753 * @return true/false 754 */ 755 private boolean isValidAssociationEnd(Object modelElement) 756 { 757 return modelElement instanceof AssociationEndFacade && ((AssociationEndFacade)modelElement).isMany(); 758 } 759 760 /** 761 * @return this.getConfiguredProperty("defaultProvider") 762 * @see org.andromda.cartridges.webservice.metafacades.WebService#getProvider() 763 */ 764 protected String handleGetProvider() 765 { 766 String provider = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_PROVIDER); 767 if (StringUtils.isBlank(provider) || provider.equals(DEFAULT)) 768 { 769 provider = (String)this.getConfiguredProperty("defaultProvider"); 770 } 771 return provider; 772 } 773 774 /** 775 * @return this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR) 776 * @see org.andromda.cartridges.webservice.metafacades.WebService#getWsdlFile() 777 */ 778 protected String handleGetWsdlFile() 779 { 780 return StringUtils.replace( 781 this.getFullyQualifiedName(), 782 String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)), 783 "/") + ".wsdl"; 784 } 785 786 /** 787 * We use this comparator to actually eliminate duplicates instead of sorting like a comparator is normally used. 788 */ 789 public final class TypeComparator 790 implements Comparator 791 { 792 private final Collator collator = Collator.getInstance(); 793 794 /** 795 * We use this comparator to actually eliminate duplicates instead of sorting like a comparator is normally used. 796 */ 797 public TypeComparator() 798 { 799 collator.setStrength(Collator.PRIMARY); 800 } 801 802 /** 803 * @see java.util.Comparator#compare(Object, Object) 804 */ 805 public int compare( 806 Object objectA, 807 Object objectB) 808 { 809 final ModelElementFacade a = (ModelElementFacade)objectA; 810 ModelElementFacade aType = getType(a); 811 if (aType == null) 812 { 813 aType = a; 814 } 815 final ModelElementFacade b = (ModelElementFacade)objectB; 816 ModelElementFacade bType = getType(b); 817 if (bType == null) 818 { 819 bType = b; 820 } 821 return collator.compare( 822 aType.getFullyQualifiedName(), 823 bType.getFullyQualifiedName()); 824 } 825 } 826 827 /** 828 * Gets the <code>type</code> or <code>returnType</code> of the model element (if the model element has a type or 829 * returnType). 830 * 831 * @param modelElement the model element we'll retrieve the type of. 832 * @return ClassifierFacade Type of modelElement Object 833 */ 834 public ClassifierFacade getType(Object modelElement) 835 { 836 try 837 { 838 final Introspector introspector = Introspector.instance(); 839 ClassifierFacade type = null; 840 String typeProperty = "type"; 841 842 // only continue if the model element has a type 843 if (introspector.isReadable(modelElement, typeProperty)) 844 { 845 type = (ClassifierFacade)introspector.getProperty(modelElement, typeProperty); 846 } 847 848 // try for return type if type wasn't found 849 typeProperty = "returnType"; 850 if (type == null && introspector.isReadable(modelElement, typeProperty)) 851 { 852 type = (ClassifierFacade)introspector.getProperty(modelElement, typeProperty); 853 } 854 // Sometimes the type is sent to this method instead of the property 855 if (type == null && modelElement instanceof ClassifierFacade) 856 { 857 type = (ClassifierFacade)modelElement; 858 } 859 return type; 860 } 861 catch (final Throwable throwable) 862 { 863 String errMsg = "Error performing WebServiceLogicImpl.getType"; 864 logger.error(errMsg, throwable); 865 throw new MetafacadeException(errMsg, throwable); 866 } 867 } 868 869 /** 870 * namespacePrefix 871 */ 872 static final String NAMESPACE_PREFIX = "namespacePrefix"; 873 874 /** 875 * @return this.getConfiguredProperty(NAMESPACE_PREFIX) 876 * @see org.andromda.cartridges.webservice.metafacades.WSDLType#getNamespacePrefix() 877 */ 878 protected String handleGetNamespacePrefix() 879 { 880 String prefix = (String)this.getConfiguredProperty(NAMESPACE_PREFIX); 881 if (StringUtils.isBlank(prefix)) 882 { 883 prefix = "impl"; 884 } 885 return prefix; 886 } 887 888 /** 889 * qualifiedNameLocalPartPattern 890 */ 891 static final String QNAME_LOCAL_PART_PATTERN = "qualifiedNameLocalPartPattern"; 892 893 /** 894 * Gets the <code>qualifiedNameLocalPartPattern</code> for this service. 895 * @return this.getConfiguredProperty(QNAME_LOCAL_PART_PATTERN) 896 */ 897 protected String getQualifiedNameLocalPartPattern() 898 { 899 String pattern = (String)this.getConfiguredProperty(QNAME_LOCAL_PART_PATTERN); 900 if (StringUtils.isBlank(pattern)) 901 { 902 pattern = "{0}"; 903 } 904 return pattern; 905 } 906 907 /** 908 * namespacePattern 909 */ 910 static final String NAMESPACE_PATTERN = "namespacePattern"; 911 912 /** 913 * Gets the <code>namespacePattern</code> for this service. 914 * 915 * @return String the namespace pattern to use. 916 */ 917 protected String getNamespacePattern() 918 { 919 String pattern = (String)this.getConfiguredProperty(NAMESPACE_PATTERN); 920 if (StringUtils.isBlank(pattern)) 921 { 922 pattern = "http://{0}/"; 923 } 924 return pattern; 925 } 926 927 /** 928 * reverseNamespace 929 */ 930 static final String REVERSE_NAMESPACE = "reverseNamespace"; 931 932 /** 933 * Gets whether or not <code>reverseNamespace</code> is true/false for this type. 934 * 935 * @return boolean true/false 936 */ 937 protected boolean isReverseNamespace() 938 { 939 return Boolean.valueOf(String.valueOf(this.getConfiguredProperty(REVERSE_NAMESPACE))).booleanValue(); 940 } 941 942 /** 943 * @return this.getEjbJndiNamePrefix() + ejb/ + this.getFullyQualifiedName() 944 * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbJndiName() 945 */ 946 protected String handleGetEjbJndiName() 947 { 948 StringBuilder jndiName = new StringBuilder(); 949 String jndiNamePrefix = StringUtils.trimToEmpty(this.getEjbJndiNamePrefix()); 950 if (StringUtils.isNotBlank(jndiNamePrefix)) 951 { 952 jndiName.append(jndiNamePrefix); 953 jndiName.append('/'); 954 } 955 jndiName.append("ejb/"); 956 jndiName.append(this.getFullyQualifiedName()); 957 return jndiName.toString(); 958 } 959 960 /** 961 * Gets the <code>ejbJndiNamePrefix</code> for an EJB provider. 962 * 963 * @return the EJB Jndi name prefix. 964 */ 965 protected String getEjbJndiNamePrefix() 966 { 967 final String property = "ejbJndiNamePrefix"; 968 return this.isConfiguredProperty(property) ? ObjectUtils.toString(this.getConfiguredProperty(property)) : null; 969 } 970 971 /** 972 * @return this.getEjbHomeInterfacePattern() formatted as this.getPackageName() + this.getName() 973 * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbHomeInterface() 974 */ 975 protected String handleGetEjbHomeInterface() 976 { 977 return MessageFormat.format( 978 this.getEjbHomeInterfacePattern(), 979 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName())); 980 } 981 982 /** 983 * Gets the <code>ejbHomeInterfacePattern</code> for an EJB provider. 984 * 985 * @return the EJB Home interface pattern 986 */ 987 protected String getEjbHomeInterfacePattern() 988 { 989 return (String)this.getConfiguredProperty("ejbHomeInterfacePattern"); 990 } 991 992 /** 993 * @return this.getEjbInterfacePattern() formatted as this.getPackageName() + this.getName() 994 * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbInterface() 995 */ 996 protected String handleGetEjbInterface() 997 { 998 return MessageFormat.format( 999 this.getEjbInterfacePattern(), 1000 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName())); 1001 } 1002 1003 /** 1004 * Gets the <code>ejbInterfacePattern</code> for an EJB provider. 1005 * 1006 * @return the EJB interface pattern 1007 */ 1008 protected String getEjbInterfacePattern() 1009 { 1010 return (String)this.getConfiguredProperty("ejbInterfacePattern"); 1011 } 1012 1013 private static final String RPC_CLASS_NAME_PATTERN = "rpcClassNamePattern"; 1014 1015 /** 1016 * Gets the <code>rpcClassNamePattern</code> for this service. 1017 * @return this.getConfiguredProperty(RPC_CLASS_NAME_PATTERN) 1018 */ 1019 protected String getRpcClassNamePattern() 1020 { 1021 return (String)this.getConfiguredProperty(RPC_CLASS_NAME_PATTERN); 1022 } 1023 1024 /** 1025 * @return this.getRpcClassNamePattern() formatted as this.getPackageName() + this.getName() 1026 * @see org.andromda.cartridges.webservice.metafacades.WebService#getRpcClassName() 1027 */ 1028 protected String handleGetRpcClassName() 1029 { 1030 return MessageFormat.format( 1031 this.getRpcClassNamePattern(), 1032 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName())); 1033 } 1034 1035 private static final String WSDL_OPERATION_SORT_MODE = "wsdlOperationSortMode"; 1036 1037 /** 1038 * Used to sort operations by <code>name</code>. 1039 */ 1040 public static final class OperationNameComparator 1041 implements Comparator 1042 { 1043 private final Collator collator = Collator.getInstance(); 1044 1045 /** 1046 * 1047 */ 1048 public OperationNameComparator() 1049 { 1050 collator.setStrength(Collator.PRIMARY); 1051 } 1052 1053 /** 1054 * @see java.util.Comparator#compare(Object, Object) 1055 */ 1056 public int compare( 1057 Object objectA, 1058 Object objectB) 1059 { 1060 ModelElementFacade a = (ModelElementFacade)objectA; 1061 ModelElementFacade b = (ModelElementFacade)objectB; 1062 1063 return collator.compare( 1064 a.getName(), 1065 b.getName()); 1066 } 1067 } 1068 1069 /** 1070 * The model specifying operations should be sorted by name. 1071 */ 1072 private static final String OPERATION_SORT_MODE_NAME = "name"; 1073 1074 /** 1075 * The model specifying operations should NOT be sorted. 1076 */ 1077 private static final String OPERATION_SORT_MODE_NONE = "none"; 1078 1079 /** 1080 * Gets the sort mode WSDL operations. 1081 * 1082 * @return String 1083 */ 1084 private String getWSDLOperationSortMode() 1085 { 1086 Object property = this.getConfiguredProperty(WSDL_OPERATION_SORT_MODE); 1087 return property != null ? (property.equals(OPERATION_SORT_MODE_NAME) ? (String)property : OPERATION_SORT_MODE_NONE) : OPERATION_SORT_MODE_NONE; 1088 } 1089 1090 /** 1091 * @return !this.getAllRoles().isEmpty() 1092 * @see org.andromda.cartridges.webservice.metafacades.WebService#isSecured() 1093 */ 1094 protected boolean handleIsSecured() 1095 { 1096 Collection<Role> roles = this.getAllRoles(); 1097 return roles != null && !roles.isEmpty(); 1098 } 1099 1100 /** 1101 * Overridden to only allow the exposed operations in the returned roles collection. 1102 * 1103 * @see org.andromda.metafacades.uml.Service#getAllRoles() 1104 */ 1105 public Collection<Role> getAllRoles() 1106 { 1107 final Collection<Role> roles = new LinkedHashSet<Role>(this.getRoles()); 1108 CollectionUtils.forAllDo( 1109 this.getAllowedOperations(), 1110 new Closure() 1111 { 1112 public void execute(Object object) 1113 { 1114 if (object != null && ServiceOperation.class.isAssignableFrom(object.getClass())) 1115 { 1116 roles.addAll(((ServiceOperation)object).getRoles()); 1117 } 1118 } 1119 }); 1120 return roles; 1121 } 1122 1123 /** 1124 * The pattern used to construct the test package name. 1125 */ 1126 private static final String TEST_PACKAGE_NAME_PATTERN = "testPackageNamePattern"; 1127 1128 /** 1129 * @return this.getPackageName() formatted as this.getConfiguredProperty(TEST_PACKAGE_NAME_PATTERN) 1130 * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestPackageName() 1131 */ 1132 protected String handleGetTestPackageName() 1133 { 1134 return String.valueOf(this.getConfiguredProperty(TEST_PACKAGE_NAME_PATTERN)).replaceAll( 1135 "\\{0\\}", 1136 this.getPackageName()); 1137 } 1138 1139 /** 1140 * @return this.getTestPackageName() + '.' + this.getTestName() 1141 * @see org.andromda.cartridges.webservice.metafacades.WebService#getFullyQualifiedTestName() 1142 */ 1143 protected String handleGetFullyQualifiedTestName() 1144 { 1145 return this.getTestPackageName() + '.' + this.getTestName(); 1146 } 1147 1148 /** 1149 * The pattern used to construct the test name. 1150 */ 1151 private static final String TEST_NAME_PATTERN = "testNamePattern"; 1152 1153 /** 1154 * @return this.getName() formatted with this.getConfiguredProperty(TEST_NAME_PATTERN) 1155 * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestName() 1156 */ 1157 protected String handleGetTestName() 1158 { 1159 return String.valueOf(this.getConfiguredProperty(TEST_NAME_PATTERN)).replaceAll( 1160 "\\{0\\}", 1161 this.getName()); 1162 } 1163 1164 /** 1165 * Represents a "wrapped" style. 1166 */ 1167 private static final String STYLE_WRAPPED = "wrapped"; 1168 1169 /** 1170 * @return this.getStyle().equalsIgnoreCase(STYLE_WRAPPED) 1171 * @see org.andromda.cartridges.webservice.metafacades.WebService#isWrappedStyle() 1172 */ 1173 protected boolean handleIsWrappedStyle() 1174 { 1175 return this.getStyle().equalsIgnoreCase(STYLE_WRAPPED); 1176 } 1177 1178 /** 1179 * Represents a "document" style. 1180 */ 1181 private static final String STYLE_DOCUMENT = "document"; 1182 1183 /** 1184 * @return this.getStyle().equalsIgnoreCase("document") 1185 * @see org.andromda.cartridges.webservice.metafacades.WebService#isDocumentStyle() 1186 */ 1187 protected boolean handleIsDocumentStyle() 1188 { 1189 return this.getStyle().equalsIgnoreCase(STYLE_DOCUMENT); 1190 } 1191 1192 /** 1193 * Represents a "rpc" style. 1194 */ 1195 private static final String STYLE_RPC = "rpc"; 1196 1197 /** 1198 * @return this.getStyle().equalsIgnoreCase("rpc") 1199 * @see org.andromda.cartridges.webservice.metafacades.WebService#isRpcStyle() 1200 */ 1201 protected boolean handleIsRpcStyle() 1202 { 1203 return this.getStyle().equalsIgnoreCase(STYLE_RPC); 1204 } 1205 1206 /** 1207 * Represents an "literal" use. 1208 */ 1209 private static final String USE_LITERAL = "literal"; 1210 1211 /** 1212 * @return this.getStyle().equalsIgnoreCase("literal") 1213 * @see org.andromda.cartridges.webservice.metafacades.WebService#isLiteralUse() 1214 */ 1215 protected boolean handleIsLiteralUse() 1216 { 1217 return this.getStyle().equalsIgnoreCase(USE_LITERAL); 1218 } 1219 1220 /** 1221 * Represents an "encoded" use. 1222 */ 1223 private static final String USE_ENCODED = "encoded"; 1224 1225 /** 1226 * @return this.getStyle().equalsIgnoreCase("encoded") 1227 * @see org.andromda.cartridges.webservice.metafacades.WebService#isEncodedUse() 1228 */ 1229 protected boolean handleIsEncodedUse() 1230 { 1231 return this.getStyle().equalsIgnoreCase(USE_ENCODED); 1232 } 1233 1234 /** 1235 * The pattern used to construct the test implementation name. 1236 */ 1237 private static final String TEST_IMPLEMENTATION_NAME_PATTERN = "testImplementationNamePattern"; 1238 1239 /** 1240 * @return this.getName() formatted as this.getConfiguredProperty(TEST_IMPLEMENTATION_NAME_PATTERN) 1241 * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestImplementationName() 1242 */ 1243 protected String handleGetTestImplementationName() 1244 { 1245 return String.valueOf(this.getConfiguredProperty(TEST_IMPLEMENTATION_NAME_PATTERN)).replaceAll( 1246 "\\{0\\}", 1247 this.getName()); 1248 } 1249 1250 /** 1251 * @return this.getTestPackageName() + '.' + this.getTestImplementationName() 1252 * @see org.andromda.cartridges.webservice.metafacades.WebService#getFullyQualifiedTestImplementationName() 1253 */ 1254 protected String handleGetFullyQualifiedTestImplementationName() 1255 { 1256 return this.getTestPackageName() + '.' + this.getTestImplementationName(); 1257 } 1258 1259 /** 1260 1261 * @return TypeMappings from WebServiceGlobals.SCHEMA_TYPE_MAPPINGS_URI "schemaTypeMappingsUri" 1262 * @see org.andromda.cartridges.webservice.metafacades.WebService#getSchemaMappings() 1263 */ 1264 protected TypeMappings handleGetSchemaMappings() 1265 { 1266 final String propertyName = WebServiceGlobals.SCHEMA_TYPE_MAPPINGS_URI; 1267 Object property = this.getConfiguredProperty(propertyName); 1268 TypeMappings mappings = null; 1269 String uri = null; 1270 if (property instanceof String) 1271 { 1272 uri = (String)property; 1273 try 1274 { 1275 mappings = TypeMappings.getInstance(uri); 1276 mappings.setArraySuffix(this.getArraySuffix()); 1277 this.setProperty(propertyName, mappings); 1278 } 1279 catch (Throwable th) 1280 { 1281 String errMsg = "Error getting '" + propertyName + "' --> '" + uri + '\''; 1282 logger.error(errMsg, th); 1283 // don't throw the exception 1284 } 1285 } 1286 else 1287 { 1288 mappings = (TypeMappings)property; 1289 } 1290 return mappings; 1291 } 1292 1293 /** 1294 * Gets the array suffix from the configured metafacade properties. 1295 * 1296 * @return the array suffix. 1297 */ 1298 private String getArraySuffix() 1299 { 1300 return String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ARRAY_NAME_SUFFIX)); 1301 } 1302 1303 /** 1304 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetAllowedOperationExceptions() 1305 */ 1306 protected Collection handleGetAllowedOperationExceptions() 1307 { 1308 final Collection exceptions = new HashSet(); 1309 1310 // collect the exceptions of all allowed operations into a single set 1311 for (final OperationFacade operation : this.getAllowedOperations()) 1312 { 1313 exceptions.addAll(operation.getExceptions()); 1314 } 1315 1316 return exceptions; 1317 } 1318 1319 /** 1320 * @return packages from this.getAllowedOperations() 1321 * @see org.andromda.cartridges.webservice.WebServiceUtils#getPackages(WebServiceLogicImpl, Set, boolean) 1322 */ 1323 public Collection<PackageFacade> getPackages() { 1324 return new WebServiceUtils().getPackages(this, (Set) this.getAllowedOperations(), true); 1325 } 1326 1327 /** 1328 * @param pkg 1329 * @return WebServiceUtils().getPkgAbbr(pkg) 1330 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl#getPkgAbbr(PackageFacade) 1331 */ 1332 public String getPkgAbbr(PackageFacade pkg) { 1333 return new WebServiceUtils().getPkgAbbr(pkg); 1334 } 1335 1336 /** 1337 * The property defining if the web service XML should be validated against the wsdl/xsd schema. 1338 */ 1339 private static final String PROPERTY_SCHEMA_VALIDATION = "schemaValidation"; 1340 private static final String BOOLEAN_FALSE = "false"; 1341 private static final String BOOLEAN_TRUE = "true"; 1342 1343 /** 1344 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsSchemaValidation() 1345 */ 1346 @Override 1347 protected boolean handleIsSchemaValidation() 1348 { 1349 String mode = (String)this.findTaggedValue(WebServiceGlobals.XML_SCHEMA_VALIDATION); 1350 if (StringUtils.isBlank(mode) || mode.equals(DEFAULT)) 1351 { 1352 mode = String.valueOf(this.getConfiguredProperty(PROPERTY_SCHEMA_VALIDATION)); 1353 } 1354 if (StringUtils.isBlank(mode) || mode.equals(DEFAULT)) 1355 { 1356 mode = BOOLEAN_FALSE; 1357 } 1358 return Boolean.parseBoolean(mode); 1359 } 1360 1361 /** 1362 * The property defining the default style to give the web services. 1363 */ 1364 private static final String PROPERTY_SIMPLE_BINDING_MODE = "simpleBindingMode"; 1365 1366 /** 1367 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsSimpleBindingMode() 1368 */ 1369 @Override 1370 protected boolean handleIsSimpleBindingMode() 1371 { 1372 String mode = (String)this.findTaggedValue(WebServiceGlobals.JAXB_SIMPLE_BINDING_MODE); 1373 if (StringUtils.isBlank(mode) || mode.equals(DEFAULT)) 1374 { 1375 mode = String.valueOf(this.getConfiguredProperty(PROPERTY_SIMPLE_BINDING_MODE)); 1376 } 1377 return Boolean.parseBoolean(mode); 1378 } 1379 1380 /** 1381 * The property defining the Jaxb XJC arguments used with wsdl2java utility. 1382 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getSchemaMappings() 1383 */ 1384 private static final String PROPERTY_XJC_ARGUMENTS = "xjcArguments"; 1385 1386 /** 1387 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getXjcArguments() 1388 */ 1389 @Override 1390 protected String handleGetXjcArguments() 1391 { 1392 String mode = (String)this.findTaggedValue(WebServiceGlobals.JAXB_XJC_ARGUMENTS); 1393 if (StringUtils.isBlank(mode) || mode.equals(DEFAULT)) 1394 { 1395 mode = String.valueOf(this.getConfiguredProperty(PROPERTY_XJC_ARGUMENTS)); 1396 } 1397 return mode; 1398 } 1399 1400 /** 1401 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestCacheType() 1402 */ 1403 @Override 1404 protected String handleGetRestCacheType() 1405 { 1406 String cacheType = (String)this.findTaggedValue(WebServiceGlobals.CACHE_TYPE); 1407 if (!(this.getRestCount()>0) || StringUtils.isBlank(cacheType) || cacheType.equals(DEFAULT)) 1408 { 1409 cacheType = EMPTY_STRING; 1410 } 1411 return cacheType; 1412 } 1413 1414 /** 1415 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestConsumes() 1416 */ 1417 @Override 1418 protected String handleGetRestConsumes() 1419 { 1420 String consumes = (String)this.findTaggedValue(WebServiceGlobals.REST_CONSUMES); 1421 if (!(this.getRestCount()>0) || StringUtils.isBlank(consumes) || consumes.equals(DEFAULT)) 1422 { 1423 consumes = EMPTY_STRING; 1424 } 1425 else 1426 { 1427 consumes = WebServiceOperationLogicImpl.translateMediaType(consumes); 1428 } 1429 return consumes; 1430 } 1431 1432 /** 1433 * Contexts should be in the form fullyqualifiedclassname variable 1434 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestContexts() 1435 */ 1436 @Override 1437 protected List<String> handleGetRestContexts() 1438 { 1439 List<String> contexts = new ArrayList<String>(); 1440 String context = (String)this.findTaggedValue(WebServiceGlobals.REST_CONTEXT); 1441 if (!(this.getRestCount()>0) || StringUtils.isBlank(context) || context.equals(DEFAULT)) 1442 { 1443 context = EMPTY_STRING; 1444 } 1445 else 1446 { 1447 // Parse comma/pipe/semicolon delimited elements into ArrayList 1448 String[] parsed = StringUtils.split(context, ",;|"); 1449 for (int i=0; i<parsed.length; i++) 1450 { 1451 contexts.add(parsed[i]); 1452 } 1453 } 1454 return contexts; 1455 } 1456 1457 /** 1458 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestMethod() 1459 */ 1460 @Override 1461 protected String handleGetRestMethod() 1462 { 1463 String method = (String)this.findTaggedValue(WebServiceGlobals.REST_HTTP_METHOD); 1464 if (!(this.getRestCount()>0) || StringUtils.isBlank(method) || method.equals(DEFAULT)) 1465 { 1466 method = EMPTY_STRING; 1467 } 1468 return method; 1469 } 1470 1471 private static final String SLASH = "/"; 1472 private static final String QUOTE = "\""; 1473 //private static final String LBRACKET = "{"; 1474 //private static final String RBRACKET = "}"; 1475 /** 1476 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestPath() 1477 */ 1478 @Override 1479 protected String handleGetRestPath() 1480 { 1481 String path = (String)this.findTaggedValue(WebServiceGlobals.REST_PATH); 1482 if (StringUtils.isBlank(path)) 1483 { 1484 path = EMPTY_STRING; 1485 } 1486 if (!(this.getRestCount()>0) || StringUtils.isBlank(path) || path.equals(DEFAULT)) 1487 { 1488 path = QUOTE + SLASH + this.getName().toLowerCase() + SLASH + QUOTE; 1489 } 1490 else 1491 { 1492 if (!path.startsWith(QUOTE)) 1493 { 1494 path = QUOTE + path; 1495 } 1496 if (!path.endsWith(QUOTE) || path.length()<2) 1497 { 1498 path = path + QUOTE; 1499 } 1500 } 1501 return path; 1502 } 1503 1504 //private static final String PRODUCE_DEFAULT = "application/xml"; 1505 /** 1506 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestProduces() 1507 */ 1508 @Override 1509 protected String handleGetRestProduces() 1510 { 1511 return WebServiceOperationLogicImpl.translateMediaType((String)this.findTaggedValue(WebServiceGlobals.REST_PRODUCES)); 1512 } 1513 1514 /** 1515 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestProvider() 1516 */ 1517 @Override 1518 protected String handleGetRestProvider() 1519 { 1520 String provider = (String)this.findTaggedValue(WebServiceGlobals.REST_PROVIDER); 1521 if (!(this.getRestCount()>0) || StringUtils.isBlank(provider) || provider.equals(DEFAULT)) 1522 { 1523 provider = EMPTY_STRING; 1524 } 1525 return provider; 1526 } 1527 1528 /** 1529 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestRetention() 1530 */ 1531 @Override 1532 protected String handleGetRestRetention() 1533 { 1534 String retention = (String)this.findTaggedValue(WebServiceGlobals.REST_RETENTION); 1535 if (!(this.getRestCount()>0) || StringUtils.isBlank(retention) || retention.equals(DEFAULT)) 1536 { 1537 retention = EMPTY_STRING; 1538 } 1539 return retention; 1540 } 1541 1542 /** 1543 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestTarget() 1544 */ 1545 @Override 1546 protected String handleGetRestTarget() 1547 { 1548 String target = (String)this.findTaggedValue(WebServiceGlobals.REST_TARGET); 1549 if (!(this.getRestCount()>0) || StringUtils.isBlank(target) || target.equals(DEFAULT)) 1550 { 1551 target = EMPTY_STRING; 1552 } 1553 return target; 1554 } 1555 1556 /** 1557 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsRestAtom() 1558 */ 1559 @Override 1560 protected boolean handleIsRestAtom() 1561 { 1562 boolean restAtom = false; 1563 if (this.getRestCount()>0) 1564 { 1565 Collection<WebServiceOperation> operations = this.getAllowedOperations(); 1566 for (WebServiceOperation operation : operations) 1567 { 1568 String restProduces = operation.getRestProduces(); 1569 if (StringUtils.isNotBlank(restProduces) && restProduces.contains("atom")) 1570 { 1571 restAtom = true; 1572 break; 1573 } 1574 } 1575 if (!restAtom) 1576 { 1577 restAtom = StringUtils.isNotBlank(this.getRestProduces()) && this.getRestProduces().indexOf("atom") > -1; 1578 } 1579 } 1580 return restAtom; 1581 } 1582 1583 /** 1584 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetRestCount() 1585 */ 1586 @Override 1587 protected int handleGetRestCount() 1588 { 1589 int restCount = 0; 1590 String rest = (String)this.findTaggedValue(WebServiceGlobals.REST); 1591 for (WebServiceOperation operation : this.getAllowedOperations()) 1592 { 1593 if (StringUtils.isNotBlank(rest) && (operation.isRest() || rest.equals(BOOLEAN_TRUE))) 1594 { 1595 restCount++; 1596 } 1597 } 1598 return restCount; 1599 } 1600 1601 /** 1602 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetJaxwsCount() 1603 */ 1604 @Override 1605 protected int handleGetJaxwsCount() 1606 { 1607 int jaxwsCount = 0; 1608 String rest = (String)this.findTaggedValue(WebServiceGlobals.REST); 1609 for (WebServiceOperation operation : this.getAllowedOperations()) 1610 { 1611 if (StringUtils.isBlank(rest) || rest.equals(BOOLEAN_FALSE) && (!operation.isRest())) 1612 { 1613 jaxwsCount++; 1614 } 1615 } 1616 return jaxwsCount; 1617 } 1618 1619 /** 1620 * Used to map between XML (list of restricted strings) and Java enum (has both a name and a value). 1621 * 1622 * @return useEnumValueInXSD true if EnumerationLiteral.value is used instead of EnumerationLiteral.Name. 1623 */ 1624 public Boolean useEnumValueInXSD() 1625 { 1626 final String propertyName = WebServiceGlobals.USE_ENUM_VALUE_IN_XSD; 1627 // getConfiguredProperty is protected so we must wrap it for use in WebServiceUtils 1628 Object property = this.getConfiguredProperty(propertyName); 1629 if (property != null && String.class.isAssignableFrom(property.getClass())) 1630 { 1631 return Boolean.valueOf(String.valueOf(property)).booleanValue(); 1632 } 1633 return Boolean.TRUE; 1634 } 1635 1636 /** 1637 * @param validationMessages Collection<ModelValidationMessage> 1638 * @see MetafacadeBase#validateInvariants(Collection validationMessages) 1639 */ 1640 @Override 1641 public void validateInvariants(Collection<ModelValidationMessage> validationMessages) 1642 { 1643 super.validateInvariants(validationMessages); 1644 try 1645 { 1646 final Object contextElement = this.THIS(); 1647 final String name = (String)OCLIntrospector.invoke(contextElement,"name"); 1648 boolean constraintValid = OCLExpressions.equal( 1649 name.substring(0,1).toUpperCase(), 1650 name.substring(0,1)); 1651 if (!constraintValid) 1652 { 1653 validationMessages.add( 1654 new ModelValidationMessage( 1655 (MetafacadeBase)contextElement , 1656 "org::andromda::cartridges::webservice::metafacades::WebService::class name must start with an uppercase letter", 1657 "WebService Class name must start with an uppercase letter.")); 1658 } 1659 } 1660 catch (Throwable th) 1661 { 1662 Throwable cause = th.getCause(); 1663 int depth = 0; // Some throwables have infinite recursion 1664 while (cause != null && depth < 7) 1665 { 1666 th = cause; 1667 depth++; 1668 } 1669 logger.error("Error validating constraint 'org::andromda::cartridges::webservice::WebService::class name must start with an uppercase letter' ON " 1670 + this.THIS().toString() + ": " + th.getMessage(), th); 1671 } 1672 } 1673}