001package org.andromda.cartridges.webservice.metafacades; 002 003import java.util.Collection; 004import java.util.HashMap; 005import java.util.Iterator; 006import java.util.Map; 007import org.andromda.cartridges.webservice.WebServiceGlobals; 008import org.andromda.cartridges.webservice.WebServiceUtils; 009import org.andromda.core.metafacade.MetafacadeBase; 010import org.andromda.core.metafacade.ModelValidationMessage; 011import org.andromda.metafacades.uml.MetafacadeUtils; 012import org.andromda.metafacades.uml.ModelElementFacade; 013import org.andromda.metafacades.uml.ParameterFacade; 014import org.andromda.metafacades.uml.Service; 015import org.andromda.metafacades.uml.UMLProfile; 016import org.andromda.translation.ocl.validation.OCLExpressions; 017import org.andromda.translation.ocl.validation.OCLIntrospector; 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020 021/** 022 * MetafacadeLogic implementation for org.andromda.cartridges.webservice.metafacades.WebServiceOperation. 023 * 024 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation 025 * @author Bob Fields 026 */ 027public class WebServiceOperationLogicImpl 028 extends WebServiceOperationLogic 029{ 030 private static final long serialVersionUID = 34L; 031 /** 032 * @param metaObject 033 * @param context 034 */ 035 public WebServiceOperationLogicImpl( 036 Object metaObject, 037 String context) 038 { 039 super(metaObject, context); 040 } 041 042 /** 043 * The logger instance. 044 */ 045 private static final Logger logger = Logger.getLogger(WebServiceOperationLogicImpl.class); 046 047 /** 048 * @return getOwner().hasStereotype(UMLProfile.STEREOTYPE_WEBSERVICE) or hasStereotype(UMLProfile.STEREOTYPE_WEBSERVICE_OPERATION) 049 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#isExposed() 050 */ 051 protected boolean handleIsExposed() 052 { 053 // Private methods are for doc and future use purposes, but are allowed. 054 boolean visibility = this.getVisibility().equals("public") || this.getVisibility().equals("protected"); 055 return visibility && (this.getOwner().hasStereotype(UMLProfile.STEREOTYPE_WEBSERVICE) || 056 this.hasStereotype(UMLProfile.STEREOTYPE_WEBSERVICE_OPERATION)); 057 } 058 059 /** 060 * The prefix given to the test implementation operation names. 061 */ 062 private static final String TEST_IMPLEMENTATION_OPERATION_NAME_PREFIX = 063 "testImplementationOperationNamePrefix"; 064 065 /** 066 * Gets the test implementation operation name prefix. 067 */ 068 private String getTestImplementationOperationNamePrefix() 069 { 070 return String.valueOf( 071 this.getConfiguredProperty(TEST_IMPLEMENTATION_OPERATION_NAME_PREFIX)); 072 } 073 074 /** 075 * @return getTestImplementationOperationNamePrefix() + StringUtils.capitalize(this.getTestName()) 076 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestImplementationName() 077 */ 078 protected String handleGetTestImplementationName() 079 { 080 return this.getTestImplementationOperationNamePrefix() + 081 StringUtils.capitalize(this.getTestName()); 082 } 083 084 /** 085 * @return "this." + this.getTestImplementationSignature() 086 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestImplementationCall() 087 */ 088 protected String handleGetTestImplementationCall() 089 { 090 return "this." + this.getTestImplementationSignature(); 091 } 092 093 /** 094 * @return this.getTestImplementationOperationNamePrefix() + StringUtils.capitalize(this.getTestSignature()) 095 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestImplementationSignature() 096 */ 097 protected String handleGetTestImplementationSignature() 098 { 099 return this.getTestImplementationOperationNamePrefix() + 100 StringUtils.capitalize(this.getTestSignature()); 101 } 102 103 /** 104 * @return Operation Signature, taking WSSecurity and WSCustomHeader annotations into account 105 * @param withArgumentNames boolean Use argument names. 106 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getSignature() 107 */ 108 protected String handleGetSignature(final boolean withArgumentNames) 109 { 110 Collection<ParameterFacade> arguments = this.getArguments(); 111 String signature = MetafacadeUtils.getSignature( 112 this.getName(), 113 arguments, 114 withArgumentNames, 115 null); 116 Service service = this.getService(); 117 if (this.hasStereotype("WSCustomHeader") || this.getService().hasStereotype("WSCustomHeader")) 118 { 119 String serviceElementName = (String) service.findTaggedValue("andromda_wsdl_header_element"); 120 String serviceNamespace = (String) service.findTaggedValue("andromda_header_namespace"); 121 String serviceClassName = WebServiceUtils.getPackageName(serviceNamespace) + '.' + serviceElementName; 122 String serviceParameterName = StringUtils.uncapitalize(serviceElementName); 123 signature = signature.substring(0, signature.length()-1); 124 if (!arguments.isEmpty()) 125 { 126 signature += ", "; 127 } 128 signature += serviceClassName; 129 if (withArgumentNames) 130 { 131 signature += " " + serviceParameterName; 132 } 133 signature += ')'; 134 } 135 if (this.hasStereotype("WSSecurity") || this.getService().hasStereotype("WSSecurity")) 136 { 137 String securityElementName = (String) service.findTaggedValue("andromda_wsdl_security_element"); 138 String securityNamespace = (String) service.findTaggedValue("andromda_security_namespace"); 139 String securityClassName = WebServiceUtils.getPackageName(securityNamespace) + '.' + securityElementName; 140 String securityParameterName = StringUtils.uncapitalize(securityElementName); 141 signature = signature.substring(0, signature.length()-1); 142 if (!arguments.isEmpty() || this.hasStereotype("WSCustomHeader") || this.getService().hasStereotype("WSCustomHeader")) 143 { 144 signature += ", "; 145 } 146 signature += securityClassName; 147 if (withArgumentNames) 148 { 149 signature += " " + securityParameterName; 150 } 151 signature += ')'; 152 } 153 return signature; 154 } 155 156 /** 157 * The prefix given to the junit test operations. 158 */ 159 private static final String TEST_NAME_PREFIX = "test"; 160 161 /** 162 * @return TEST_NAME_PREFIX + StringUtils.capitalize(this.getName()) 163 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestName() 164 */ 165 protected String handleGetTestName() 166 { 167 return TEST_NAME_PREFIX + StringUtils.capitalize(this.getName()); 168 } 169 170 /** 171 * @return "this." + this.getSignature() 172 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestCall() 173 */ 174 protected String handleGetTestCall() 175 { 176 return "this." + this.getSignature(); 177 } 178 179 /** 180 * @return this.getTestName() + "()" 181 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperation#getTestSignature() 182 */ 183 protected String handleGetTestSignature() 184 { 185 return this.getTestName() + "()"; 186 } 187 188 /** 189 * The property defining the default style to give the web services. 190 */ 191 private static final String PROPERTY_DEFAULT_PARAMETER_STYLE = "defaultParameterStyle"; 192 private static final String DEFAULT = "default"; 193 private static final String EMPTY_STRING = ""; 194 private static final String BOOLEAN_FALSE = "false"; 195 196 /** 197 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#handleGetParameterStyle() 198 */ 199 @Override 200 protected String handleGetParameterStyle() 201 { 202 String style = (String)this.findTaggedValue(WebServiceGlobals.WEB_SERVICE_PARAMETER_STYLE); 203 if (StringUtils.isEmpty(style) || style.equals(DEFAULT)) 204 { 205 style = String.valueOf(this.getConfiguredProperty(PROPERTY_DEFAULT_PARAMETER_STYLE)); 206 } 207 if (StringUtils.isEmpty(style) || style.equals(DEFAULT)) 208 { 209 style = "wrapped"; 210 } 211 return style; 212 } 213 /** 214 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestCacheType() 215 */ 216 @Override 217 protected String handleGetRestCacheType() 218 { 219 String cacheType = (String)this.findTaggedValue(WebServiceGlobals.CACHE_TYPE); 220 if (!this.isRest() || StringUtils.isBlank(cacheType) || cacheType.equals(DEFAULT)) 221 { 222 cacheType = EMPTY_STRING; 223 } 224 return cacheType; 225 } 226 227 /** 228 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestConsumes() 229 */ 230 @Override 231 protected String handleGetRestConsumes() 232 { 233 String consumes = (String)this.findTaggedValue(WebServiceGlobals.REST_CONSUMES); 234 if (!this.isRest() || StringUtils.isBlank(consumes) || consumes.equals(DEFAULT)) 235 { 236 consumes = EMPTY_STRING; 237 } 238 else 239 { 240 consumes = translateMediaType(consumes); 241 } 242 return consumes; 243 } 244 245 /** 246 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestPartType() 247 */ 248 @Override 249 protected String handleGetRestPartType() 250 { 251 String partType = (String)this.findTaggedValue(WebServiceGlobals.REST_PART_TYPE); 252 if (!this.isRest() || StringUtils.isBlank(partType) || partType.equals(DEFAULT)) 253 { 254 partType = EMPTY_STRING; 255 } 256 return partType; 257 } 258 259 private static final String SLASH = "/"; 260 private static final String QUOTE = "\""; 261 private static final String LBRACKET = "{"; 262 private static final String RBRACKET = "}"; 263 /** 264 * Create default REST URL of /methodname/parameter/{parameter}/ 265 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestPath() 266 */ 267 @Override 268 protected String handleGetRestPath() 269 { 270 String path = (String)this.findTaggedValue(WebServiceGlobals.REST_PATH); 271 StringBuilder pathBuffer = new StringBuilder(); 272 if (!this.isRest() || StringUtils.isBlank(path) || path.equals(DEFAULT)) 273 { 274 pathBuffer.append(QUOTE).append(SLASH).append(this.getName().toLowerCase()).append(SLASH); 275 //path = SLASH + this.getName().toLowerCase() + SLASH; 276 Iterator<ParameterFacade> parameters = this.getArguments().iterator(); 277 while (parameters.hasNext()) 278 { 279 ParameterFacade param = parameters.next(); 280 //if (WebServiceUtils.isSimpleType(param)) 281 //{ 282 String paramName = param.getName(); 283 pathBuffer.append(paramName).append(SLASH).append(LBRACKET).append(paramName).append(RBRACKET).append(SLASH); 284 //} 285 } 286 pathBuffer.append(QUOTE); 287 } 288 else 289 { 290 if (StringUtils.isBlank(path)) 291 { 292 path = EMPTY_STRING; 293 } 294 pathBuffer.append(path); 295 if (!path.startsWith(QUOTE)) 296 { 297 pathBuffer.insert(0, QUOTE); 298 } 299 if (!path.endsWith(QUOTE) || path.length()<2) 300 { 301 pathBuffer.append(QUOTE); 302 } 303 } 304 return pathBuffer.toString(); 305 } 306 307 /** 308 * Create test REST URL of /methodname/parameter/{parameter}/ 309 * Substitutes test values for parameters 310 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestPath() 311 */ 312 @Override 313 protected String handleGetRestTestPath() 314 { 315 String path = (String)this.findTaggedValue(WebServiceGlobals.REST_PATH); 316 StringBuilder pathBuffer = new StringBuilder(); 317 WebServiceLogic service = (WebServiceLogic)this.getService(); 318 String servicePath = service.getRestPath(); 319 WebServiceUtils wsutils = new WebServiceUtils(); 320 if (!this.isRest() || StringUtils.isBlank(path) || path.equals(DEFAULT)) 321 { 322 pathBuffer.append(SLASH).append(this.getName().toLowerCase()).append(SLASH); 323 Iterator<ParameterFacade> parameters = this.getArguments().iterator(); 324 while (parameters.hasNext()) 325 { 326 ParameterFacade param = parameters.next(); 327 //System.out.println("handleGetRestTestPath param=" + param.getName() + " servicePath=" + servicePath + " value=" + wsutils.createConstructor(param)); 328 if (WebServiceUtils.isSimpleType(param)) 329 { 330 String paramValue = wsutils.createConstructor(param); 331 // Only use the value if constructor returns new Class() 332 if (paramValue.indexOf('(') > 0) 333 { 334 paramValue = paramValue.substring(paramValue.indexOf('(')+1, paramValue.indexOf(')')); 335 } 336 pathBuffer.append(param.getName()).append(SLASH).append(paramValue).append(SLASH); 337 } 338 } 339 path = pathBuffer.toString(); 340 } 341 else 342 { 343 if (StringUtils.isBlank(path)) 344 { 345 path = EMPTY_STRING; 346 } 347 // StringBuffer doesn't have replace(String, String) API 348 path = pathBuffer.append(path).toString(); 349 Iterator<ParameterFacade> parameters = this.getArguments().iterator(); 350 while (parameters.hasNext()) 351 { 352 ParameterFacade param = parameters.next(); 353 if (WebServiceUtils.isSimpleType(param)) 354 { 355 String paramValue = wsutils.createConstructor(param).replace("\"", ""); 356 if (paramValue.indexOf('(') > 0) 357 { 358 paramValue = paramValue.substring(paramValue.indexOf('(')+1, paramValue.indexOf(')')); 359 } 360 path = StringUtils.replace(path, LBRACKET + param.getName() + RBRACKET, paramValue); 361 } 362 //System.out.println("handleGetRestTestPath param=" + param.getName() + " servicePath=" + servicePath + " value=" + wsutils.createConstructor(param) + " path=" + path); 363 } 364 } 365 path = servicePath + path; 366 path = path.replaceAll("\"", ""); 367 path = path.replaceAll("//", "/"); 368 return path; 369 } 370 371 /** 372 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestProduces() 373 */ 374 @Override 375 protected String handleGetRestProduces() 376 { 377 String produces = (String)this.findTaggedValue(WebServiceGlobals.REST_PRODUCES); 378 // default types: text for simple types, XML for complex types 379 if (!this.isRest() || produces == DEFAULT) 380 { 381 // See if the service class has REST_produces attribute set... 382 produces = (String)this.getOwner().findTaggedValue(WebServiceGlobals.REST_PRODUCES); 383 if (produces == DEFAULT) 384 { 385 // Default produces type for simple or complex return types 386 if (WebServiceUtils.isSimpleType(this.getReturnType())) 387 { 388 produces = "text/plain"; 389 } 390 else 391 { 392 produces = "application/xml"; 393 } 394 } 395 } 396 else 397 { 398 produces = translateMediaType(produces); 399 } 400 return produces; 401 } 402 403 /** 404 * Returns map of ProviderMediaType enumeration values to Provider/Consumer text 405 */ 406 private static Map<String, String> getMediaTranslation() 407 { 408 final Map<String, String> mediaMap = new HashMap<String, String>(); 409 mediaMap.put("default", QUOTE + "application/xml" + QUOTE); 410 mediaMap.put("ApplicationAtom", QUOTE + "application/atom+xml" + QUOTE); 411 mediaMap.put("ApplicationAtomEntry", QUOTE + "application/atom+xml;type=entry" + QUOTE); 412 mediaMap.put("ApplicationAtomXML", QUOTE + "application/atom+xml" + QUOTE); 413 mediaMap.put("ApplicationFastinfoset", QUOTE + "application/fastinfoset" + QUOTE); 414 mediaMap.put("ApplicationFormURLEncoded", QUOTE + "application/x-www-form-urlencoded" + QUOTE); 415 mediaMap.put("ApplicationJSON", QUOTE + "application/json" + QUOTE); 416 mediaMap.put("ApplicationOctetStream", QUOTE + "application/octet-stream" + QUOTE); 417 mediaMap.put("ApplicationSvgXML", QUOTE + "application/svg+xml" + QUOTE); 418 mediaMap.put("ApplicationXhtmlXML", QUOTE + "application/xhtml+xml" + QUOTE); 419 mediaMap.put("ApplicationXML", QUOTE + "application/xml" + QUOTE); 420 mediaMap.put("ApplicationXMLAll", QUOTE + "application/*+xml" + QUOTE); 421 mediaMap.put("ApplicationYaml", QUOTE + "application/yaml" + QUOTE); 422 mediaMap.put("MultipartAlternative", QUOTE + "multipart/alternative" + QUOTE); 423 mediaMap.put("MultipartFixed", QUOTE + "multipart/fixed" + QUOTE); 424 mediaMap.put("MultipartFormData", QUOTE + "multipart/form-data" + QUOTE); 425 mediaMap.put("MultipartMixed", QUOTE + "multipart/mixed" + QUOTE); 426 mediaMap.put("MultipartRelated", QUOTE + "multipart/related" + QUOTE); 427 mediaMap.put("TextPlain", QUOTE + "text/plain" + QUOTE); 428 mediaMap.put("TextXML", QUOTE + "text/xml" + QUOTE); 429 mediaMap.put("TextXYaml", QUOTE + "text/xyaml" + QUOTE); 430 mediaMap.put("TextYaml", QUOTE + "text/xml" + QUOTE); 431 mediaMap.put("Wildcard", QUOTE + "*/*" + QUOTE); 432 return mediaMap; 433 } 434 435 /** 436 * Translates Media Enumeration Type into string for produces/consumes annotation 437 * @param input ProviderMediaType Enumeration value to be translated for Annotation 438 * @return getMediaTranslation().get(input) 439 */ 440 public static String translateMediaType(String input) 441 { 442 String output = null; 443 if (StringUtils.isBlank(input) || input.equals(DEFAULT) || !getMediaTranslation().containsKey(input)) 444 { 445 output = getMediaTranslation().get(DEFAULT); 446 } 447 else 448 { 449 output = getMediaTranslation().get(input); 450 } 451 return output; 452 } 453 454 /** 455 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestProvider() 456 */ 457 @Override 458 protected String handleGetRestProvider() 459 { 460 String provider = (String)this.findTaggedValue(WebServiceGlobals.REST_PROVIDER); 461 if (!this.isRest() || StringUtils.isBlank(provider) || provider.equals(DEFAULT)) 462 { 463 provider = EMPTY_STRING; 464 } 465 return provider; 466 } 467 468 private static final String GET = "@javax.ws.rs.GET"; 469 private static final String AT = "@javax.ws.rs."; 470 /** 471 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestRequestType() 472 */ 473 @Override 474 protected String handleGetRestRequestType() 475 { 476 String requestType = (String)this.findTaggedValue(WebServiceGlobals.REST_REQUEST_TYPE); 477 if (!this.isRest() || StringUtils.isBlank(requestType) || requestType.equals(DEFAULT)) 478 { 479 requestType = GET; 480 } 481 else if (!requestType.startsWith(AT)) 482 { 483 requestType = AT + requestType; 484 } 485 return requestType; 486 } 487 488 /** 489 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRestRequestType() 490 */ 491 @Override 492 protected int handleGetRestSuspend() 493 { 494 String suspend = (String)this.findTaggedValue(WebServiceGlobals.REST_SUSPEND); 495 if (!this.isRest() || StringUtils.isBlank(suspend) || suspend.equals(DEFAULT) || !StringUtils.isNumeric(suspend)) 496 { 497 return 0; 498 } 499 return Integer.parseInt(suspend); 500 } 501 502 /** 503 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRolesAllowed() 504 */ 505 @Override 506 protected String handleGetRolesAllowed() 507 { 508 String rolesAllowed = (String)this.findTaggedValue(WebServiceGlobals.REST_ROLES_ALLOWED); 509 if (!this.isRest() || StringUtils.isBlank(rolesAllowed) || rolesAllowed.equals(DEFAULT)) 510 { 511 rolesAllowed = EMPTY_STRING; 512 } 513 return rolesAllowed; 514 } 515 516 /** 517 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#handleIsRest() 518 */ 519 @Override 520 protected boolean handleIsRest() 521 { 522 String rest = (String)this.findTaggedValue(WebServiceGlobals.REST); 523 if (StringUtils.isBlank(rest) || rest.equals(DEFAULT)) 524 { 525 rest = (String)this.getOwner().findTaggedValue(WebServiceGlobals.REST); 526 if (StringUtils.isBlank(rest) || rest.equals(DEFAULT)) 527 { 528 rest = BOOLEAN_FALSE; 529 } 530 } 531 return Boolean.valueOf(rest); 532 } 533 534 /** 535 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#getRolesAllowed() 536 */ 537 @Override 538 protected boolean handleIsRestEncoded() 539 { 540 String restEncoded = (String)this.findTaggedValue(WebServiceGlobals.REST_ENCODED); 541 if (!this.isRest() || StringUtils.isBlank(restEncoded) || restEncoded.equals(DEFAULT)) 542 { 543 restEncoded = BOOLEAN_FALSE; 544 } 545 return Boolean.valueOf(restEncoded); 546 } 547 548 /** 549 * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#isRestAtom() 550 */ 551 @Override 552 protected boolean handleIsRestAtom() 553 { 554 WebServiceLogic service = (WebServiceLogic)this.getService(); 555 boolean rest = this.isRest(); 556 boolean restAtom = false; 557 if (rest) 558 { 559 restAtom = this.getRestProduces().contains("atom"); 560 if (!restAtom) 561 { 562 restAtom = service.getRestProduces().indexOf("atom") > -1; 563 } 564 } 565 return restAtom; 566 } 567 568 /** 569 * Return the value from WebServiceOperation andromda_webservice_operationName, or just the operation.name 570 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#handleGetOperationName() 571 */ 572 @Override 573 protected String handleGetOperationName() 574 { 575 String serviceName = (String)this.findTaggedValue(WebServiceGlobals.WEB_SERVICE_NAME); 576 if (StringUtils.isBlank(serviceName)) 577 { 578 serviceName = this.getName(); 579 } 580 return serviceName; 581 } 582 583 /** 584 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#handleIsWebFaultOnAllExceptions() 585 */ 586 @Override 587 protected boolean handleIsWebFaultOnAllExceptions() 588 { 589 boolean result = true; 590 String webserviceStack = String.valueOf(this.getConfiguredProperty("webserviceStack")); 591 if (webserviceStack.equals("cxf") || webserviceStack.equals("jaxws")) 592 { 593 Collection<ModelElementFacade> exceptions = this.getExceptions(); 594 for (ModelElementFacade exception : exceptions) 595 { 596 // Log the missing exception class, since validation message only shows the service operation name 597 if (!exception.hasStereotype(UMLProfile.STEREOTYPE_WEB_FAULT)) 598 { 599 result = false; 600 logger.warn(exception.getFullyQualifiedName() + " WebFault stereotype missing from operation exception thrown by " + this.getFullyQualifiedName()); 601 } 602 } 603 } 604 return result; 605 } 606 607 /** 608 * @see org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogic#handleGetWebServicePackage() 609 */ 610 @Override 611 protected ModelElementFacade handleGetWebServicePackage() 612 { 613 return this.getOwner().getPackage(); 614 } 615 616 /** 617 * <p><b>Constraint:</b> org::andromda::cartridges::webservice::metafacades::WebServiceOperation::operation must start with a lowercase letter</p> 618 * <p><b>Error:</b> Operation name must start with a lowercase letter.</p> 619 * @param validationMessages Collection<ModelValidationMessage> 620 * @see MetafacadeBase#validateInvariants(Collection validationMessages) 621 */ 622 @Override 623 public void validateInvariants(Collection<ModelValidationMessage> validationMessages) 624 { 625 super.validateInvariants(validationMessages); 626 try 627 { 628 final Object contextElement = this.THIS(); 629 final String name = (String)OCLIntrospector.invoke(contextElement,"name"); 630 boolean constraintValid = OCLExpressions.equal( 631 name.substring(0,1).toLowerCase(), 632 name.substring(0,1)); 633 if (!constraintValid) 634 { 635 validationMessages.add( 636 new ModelValidationMessage( 637 (MetafacadeBase)contextElement , 638 "org::andromda::cartridges::webservice::metafacades::WebServiceOperation::operation must start with a lowercase letter", 639 "Operation name must start with a lowercase letter.")); 640 } 641 } 642 catch (Throwable th) 643 { 644 Throwable cause = th.getCause(); 645 int depth = 0; // Some throwables have infinite recursion 646 while (cause != null && depth < 7) 647 { 648 th = cause; 649 depth++; 650 } 651 logger.error("Error validating constraint 'org::andromda::cartridges::webservice::WebServicePackage::operation must start with a lowercase letter' ON " 652 + this.THIS().toString() + ": " + th.getMessage(), th); 653 } 654 } 655}