001package org.andromda.translation.ocl.validation; 002 003import java.io.InputStream; 004import java.net.URL; 005import java.util.HashMap; 006import java.util.Iterator; 007import java.util.List; 008import java.util.Map; 009import java.util.Properties; 010import java.util.Stack; 011import org.andromda.core.engine.ModelProcessorException; 012import org.andromda.core.translation.TranslationUtils; 013import org.andromda.metafacades.uml.ModelElementFacade; 014import org.andromda.translation.ocl.BaseTranslator; 015import org.andromda.translation.ocl.node.*; 016import org.andromda.translation.ocl.syntax.ConcreteSyntaxUtils; 017import org.andromda.translation.ocl.syntax.OCLFeatures; 018import org.andromda.translation.ocl.syntax.OCLPatterns; 019import org.apache.commons.lang.StringUtils; 020 021/** 022 * <p/> 023 * Provides translation of OCL validation constraints to the Java language. </p> 024 * 025 * @author Wouter Zoons 026 * @author Chad Brandon 027 */ 028public class ValidationJavaTranslator 029 extends BaseTranslator 030{ 031 private static Properties features = null; 032 033 static 034 { 035 try 036 { 037 URL featuresUri = ValidationJavaTranslator.class.getResource("features.properties"); 038 if (featuresUri == null) 039 { 040 throw new ModelProcessorException("Could not load file --> '" + featuresUri + '\''); 041 } 042 features = new Properties(); 043 InputStream stream = featuresUri.openStream(); 044 features.load(stream); 045 stream.close(); 046 stream = null; 047 } 048 catch (final Throwable throwable) 049 { 050 throw new ValidationTranslatorException(throwable); 051 } 052 } 053 054 /** 055 * The package to which the OCL translator classes belong. 056 */ 057 private static final String OCL_TRANSLATOR_PACKAGE = "org.andromda.translation.ocl.validation"; 058 059 /** 060 * This is the start of a new constraint. We prepare everything by resetting and initializing the required objects. 061 * @param node 062 */ 063 public void caseAContextDeclaration(AContextDeclaration node) 064 { 065 newTranslationLayer(); 066 { 067 Object[] temp = node.getContextDeclaration().toArray(); 068 for (int ctr = 0; ctr < temp.length; ctr++) 069 { 070 ((PContextDeclaration) temp[ctr]).apply(this); 071 } 072 } 073 mergeTranslationLayers(); 074 this.getExpression().appendToTranslatedExpression(translationLayers.peek()); 075 translationLayers.clear(); 076 } 077 078 /** 079 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAClassifierContextDeclaration(org.andromda.translation.ocl.node.AClassifierContextDeclaration) 080 */ 081 public void caseAClassifierContextDeclaration(AClassifierContextDeclaration node) 082 { 083 // explicitly call super method so 084 // that we can set the type of the expression 085 super.inAClassifierContextDeclaration(node); 086 Object[] temp = node.getClassifierExpressionBody().toArray(); 087 for (int ctr = 0; ctr < temp.length; ctr++) 088 ((PClassifierExpressionBody) temp[ctr]).apply(this); 089 } 090 091 /** 092 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAOperationContextDeclaration(org.andromda.translation.ocl.node.AOperationContextDeclaration) 093 */ 094 public void caseAOperationContextDeclaration(AOperationContextDeclaration node) 095 { 096 // explicitly call super method so 097 // that we can set the type of the expression 098 super.inAOperationContextDeclaration(node); 099 Object[] temp = node.getOperationExpressionBody().toArray(); 100 for (int ctr = 0; ctr < temp.length; ctr++) 101 ((POperationExpressionBody) temp[ctr]).apply(this); 102 } 103 104 /** 105 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAAttributeOrAssociationContextDeclaration(org.andromda.translation.ocl.node.AAttributeOrAssociationContextDeclaration) 106 */ 107 public void caseAAttributeOrAssociationContextDeclaration(AAttributeOrAssociationContextDeclaration node) 108 { 109 super.inAAttributeOrAssociationContextDeclaration(node); 110 Object[] temp = node.getAttributeOrAssociationExpressionBody().toArray(); 111 for (int ctr = 0; ctr < temp.length; ctr++) 112 ((PAttributeOrAssociationExpressionBody) temp[ctr]).apply(this); 113 } 114 115 /** 116 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAInvClassifierExpressionBody(org.andromda.translation.ocl.node.AInvClassifierExpressionBody) 117 */ 118 public void caseAInvClassifierExpressionBody(AInvClassifierExpressionBody node) 119 { 120 // explicitly call super method so 121 // that we can set the type of the expression 122 super.inAInvClassifierExpressionBody(node); 123 node.getExpression().apply(this); 124 } 125 126 /** 127 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseADefClassifierExpressionBody(org.andromda.translation.ocl.node.ADefClassifierExpressionBody) 128 */ 129 public void caseADefClassifierExpressionBody(ADefClassifierExpressionBody node) 130 { 131 // explicitly call super method so 132 // that we can set the type of the expression 133 super.inADefClassifierExpressionBody(node); 134 node.getDefinitionExpression().apply(this); 135 } 136 137 /** 138 * We need to keep track that what follows is in the scope of an arrow feature call, this is important because it 139 * means it is a feature that is implied by the OCL language, rather than the model on which the constraint 140 * applies. 141 * @param node 142 */ 143 public void inAArrowPropertyCallExpressionTail(AArrowPropertyCallExpressionTail node) 144 { 145 this.arrowPropertyCallStack.push(Boolean.TRUE); 146 } 147 148 /** 149 * Undo the arrow feature call trace. 150 * @param node 151 */ 152 public void outAArrowPropertyCallExpressionTail(AArrowPropertyCallExpressionTail node) 153 { 154 this.arrowPropertyCallStack.pop(); 155 } 156 157 /** 158 * This indicates we have entered a feature call, we need to mark this to counterpart any previous arrow feature 159 * call flags. 160 * @param node 161 */ 162 public void inADotPropertyCallExpressionTail(ADotPropertyCallExpressionTail node) 163 { 164 this.arrowPropertyCallStack.push(Boolean.FALSE); 165 } 166 167 /** 168 * Undo the dot feature call trace. 169 * @param node 170 */ 171 public void outADotPropertyCallExpressionTail(ADotPropertyCallExpressionTail node) 172 { 173 this.arrowPropertyCallStack.pop(); 174 } 175 176 /** 177 * Here we need to make sure the equals sign '=' is not translated into the 'equal' keyword. OCL uses '=' for 178 * comparison as well as for assignment, Java uses '==', '=' and .equals() so we override the default OCL value here 179 * to use '=' instead of 'equal' 180 * @param node 181 */ 182 public void caseALetVariableDeclaration(ALetVariableDeclaration node) 183 { 184 inALetVariableDeclaration(node); 185 if (node.getVariableDeclaration() != null) 186 { 187 node.getVariableDeclaration().apply(this); 188 } 189 if (node.getEqual() != null) 190 { 191 write("="); 192 } 193 if (node.getExpression() != null) 194 { 195 node.getExpression().apply(this); 196 } 197 outALetVariableDeclaration(node); 198 } 199 200 /** 201 * Add a variable to the context. 202 * @param node 203 */ 204 public void inALetVariableDeclaration(ALetVariableDeclaration node) 205 { 206 newTranslationLayer(); // this layer will be disposed later on, we do 207 // not write variable declarations 208 209 AVariableDeclaration variableDeclaration = (AVariableDeclaration) node.getVariableDeclaration(); 210 String variableName = variableDeclaration.getName().getText(); 211 212 newTranslationLayer(); 213 node.getExpression().apply(this); 214 215 String variableValue = translationLayers.pop().toString(); 216 217 addLetVariableToContext(variableName, variableValue); 218 } 219 220 /** 221 * In Java we need to end the declaration statement with a semicolon, this is handled here. 222 * @param node 223 */ 224 public void outALetVariableDeclaration(ALetVariableDeclaration node) 225 { 226 write(";"); 227 translationLayers.pop(); 228 } 229 230 /** 231 * Renders a variable declaration. Missing types will imply the Object type. 232 * @param node 233 */ 234 public void caseAVariableDeclaration(AVariableDeclaration node) 235 { 236 if (node.getTypeDeclaration() == null) 237 write("Object"); 238 else 239 node.getTypeDeclaration().apply(this); 240 241 write(" "); // we need to add a space between the type and the name 242 243 node.getName().apply(this); 244 } 245 246 /** 247 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseATypeDeclaration(org.andromda.translation.ocl.node.ATypeDeclaration) 248 */ 249 public void caseATypeDeclaration(ATypeDeclaration node) 250 { 251 node.getType().apply(this); 252 } 253 254 /** 255 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAVariableDeclarationList(org.andromda.translation.ocl.node.AVariableDeclarationList) 256 */ 257 public void caseAVariableDeclarationList(AVariableDeclarationList node) 258 { 259 node.getVariableDeclaration().apply(this); 260 261 if (node.getVariableDeclarationValue() != null) 262 node.getVariableDeclarationValue().apply(this); 263 264 Object[] temp = node.getVariableDeclarationListTail().toArray(); 265 for (int ctr = 0; ctr < temp.length; ctr++) 266 ((PVariableDeclarationListTail) temp[ctr]).apply(this); 267 } 268 269 /** 270 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAVariableDeclarationListTail(org.andromda.translation.ocl.node.AVariableDeclarationListTail) 271 */ 272 public void caseAVariableDeclarationListTail(AVariableDeclarationListTail node) 273 { 274 node.getComma().apply(this); 275 node.getVariableDeclaration().apply(this); 276 277 if (node.getVariableDeclarationValue() != null) 278 node.getVariableDeclarationValue().apply(this); 279 } 280 281 /** 282 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAEqualExpression(org.andromda.translation.ocl.node.AEqualExpression) 283 */ 284 public void caseAEqualExpression(AEqualExpression node) 285 { 286 node.getEqual().apply(this); 287 node.getExpression().apply(this); 288 } 289 290 /** 291 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseABodyOperationStereotype(org.andromda.translation.ocl.node.ABodyOperationStereotype) 292 */ 293 public void caseABodyOperationStereotype(ABodyOperationStereotype node) 294 { 295 } 296 297 /** 298 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAPreOperationStereotype(org.andromda.translation.ocl.node.APreOperationStereotype) 299 */ 300 public void caseAPreOperationStereotype(APreOperationStereotype node) 301 { 302 } 303 304 /** 305 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAPostOperationStereotype(org.andromda.translation.ocl.node.APostOperationStereotype) 306 */ 307 public void caseAPostOperationStereotype(APostOperationStereotype node) 308 { 309 } 310 311 /** 312 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAMessageExpression(org.andromda.translation.ocl.node.AMessageExpression) 313 */ 314 public void caseAMessageExpression(AMessageExpression node) 315 { 316 } 317 318 /** 319 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAIfExpression(org.andromda.translation.ocl.node.AIfExpression) 320 */ 321 public void caseAIfExpression(AIfExpression node) 322 { 323 node.getIf().apply(this); 324 325 write("("); 326 node.getIfBranch().apply(this); 327 write(")"); 328 329 node.getThen().apply(this); 330 331 write("{"); 332 node.getThenBranch().apply(this); 333 write(";"); 334 write("}"); 335 336 node.getElse().apply(this); 337 338 write("{"); 339 node.getElseBranch().apply(this); 340 write(";"); 341 write("}"); 342 } 343 344 /** 345 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAPropertyCallExpression(org.andromda.translation.ocl.node.APropertyCallExpression) 346 */ 347 public void caseAPropertyCallExpression(APropertyCallExpression node) 348 { 349 newTranslationLayer(); 350 node.getPrimaryExpression().apply(this); 351 Object[] temp = node.getPropertyCallExpressionTail().toArray(); 352 for (int ctr = 0; ctr < temp.length; ctr++) 353 ((PPropertyCallExpressionTail) temp[ctr]).apply(this); 354 mergeTranslationLayerAfter(); 355 } 356 357 /** 358 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseADotPropertyCallExpressionTail(org.andromda.translation.ocl.node.ADotPropertyCallExpressionTail) 359 */ 360 public void caseADotPropertyCallExpressionTail(ADotPropertyCallExpressionTail node) 361 { 362 inADotPropertyCallExpressionTail(node); 363 String expression = TranslationUtils.trimToEmpty(node); 364 // we prepend an introspection call if the expression is 365 // an operation call 366 if (OCLPatterns.isOperation(expression)) 367 { 368 AFeatureCall featureCall = (AFeatureCall) node.getFeatureCall(); 369 String featureCallExpression = TranslationUtils.trimToEmpty(node.getFeatureCall()); 370 if (OCLFeatures.isOclIsKindOf(featureCallExpression)) 371 { 372 this.handleOclIsKindOf(featureCall); 373 } else if (OCLFeatures.isOclIsTypeOf(featureCallExpression)) 374 { 375 this.handleOclIsTypeOf(featureCall); 376 } else if (OCLFeatures.isConcat(featureCallExpression)) 377 { 378 this.handleConcat(featureCall); 379 } else 380 { 381 this.handleDotFeatureCall(featureCall); 382 } 383 } 384 outADotPropertyCallExpressionTail(node); 385 } 386 387 /** 388 * oclIsKindOf(type) is a special feature defined by OCL on all objects. 389 */ 390 private void handleOclIsKindOf(Object node) 391 { 392 String type = this.getParametersAsType(node); 393 if (type != null) 394 { 395 write(" instanceof "); 396 write(type); 397 } 398 } 399 400 /** 401 * oclIsTypeOf(type) is a special feature defined by OCL on all objects. 402 */ 403 private void handleOclIsTypeOf(Object node) 404 { 405 String type = this.getParametersAsType(node); 406 if (type != null) 407 { 408 write(".getClass().getName().equals("); 409 write(type); 410 write(".class.getName())"); 411 } 412 } 413 414 /** 415 * Extracts the parameters from the given <code>node</code> and returns the parameters as a type (or null if none 416 * can be extracted). 417 * 418 * @param node the node from which to extrac the parameters 419 * @return the fully qualified type name. 420 */ 421 private String getParametersAsType(Object node) 422 { 423 String type = null; 424 if (node instanceof AFeatureCall) 425 { 426 type = ConcreteSyntaxUtils.getParametersAsString((AFeatureCall) node); 427 } else if (node instanceof AFeatureCallParameters) 428 { 429 type = ConcreteSyntaxUtils.getParametersAsString((AFeatureCallParameters) node); 430 } 431 if (type != null) 432 { 433 type = type.replaceAll("\\s*::\\s*", "."); 434 // if we don't have a package define, attempt to find the model 435 // element 436 // in the same package as the context element. 437 if (type.indexOf('.') == -1) 438 { 439 if (this.getModelElement() != null) 440 { 441 type = this.getModelElement().getPackageName() + '.' + type; 442 } 443 } 444 } 445 return type; 446 } 447 448 /** 449 * contact(string) is a special feature defined by OCL on strings. 450 */ 451 private void handleConcat(AFeatureCall featureCall) 452 { 453 write(" + \"\" + "); 454 write(OCL_INTROSPECTOR_INVOKE_PREFIX); 455 write(CONTEXT_ELEMENT_NAME); 456 write(",\""); 457 write(ConcreteSyntaxUtils.getParametersAsString(featureCall).replaceAll("\\s*", "")); 458 write("\")"); 459 } 460 461 /** 462 * Handles a <strong>dot </strong> feature call. Its expected that this <code>featureCall</code>'s parent is a 463 * ADotPropertyCallExpressionTail. This is here because dot feature calls must be handled differently than 464 * <code>arrow<code> feature calls. 465 * 466 * @param featureCall the <strong>dot</strong> <code>featureCall</code> to handle. 467 */ 468 public void handleDotFeatureCall(AFeatureCall featureCall) 469 { 470 this.prependToTranslationLayer(OCL_INTROSPECTOR_INVOKE_PREFIX); 471 this.appendToTranslationLayer(",\""); 472 this.appendToTranslationLayer(TranslationUtils.deleteWhitespace(featureCall)); 473 this.appendToTranslationLayer("\""); 474 if (featureCall.getFeatureCallParameters() != null) 475 { 476 List parameters = ConcreteSyntaxUtils.getParameters(featureCall); 477 if (parameters != null && !parameters.isEmpty()) 478 { 479 write(",new Object[]{"); 480 this.appendToTranslationLayer(OCL_INTROSPECTOR_INVOKE_PREFIX); 481 this.appendToTranslationLayer(CONTEXT_ELEMENT_NAME); 482 this.appendToTranslationLayer(",\""); 483 this.appendToTranslationLayer(ConcreteSyntaxUtils.getParameters(featureCall).get(0)); 484 this.appendToTranslationLayer("\")}"); 485 } 486 } 487 this.appendToTranslationLayer(")"); 488 } 489 490 /** 491 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAArrowPropertyCallExpressionTail(org.andromda.translation.ocl.node.AArrowPropertyCallExpressionTail) 492 */ 493 public void caseAArrowPropertyCallExpressionTail(AArrowPropertyCallExpressionTail node) 494 { 495 inAArrowPropertyCallExpressionTail(node); 496 node.getArrow().apply(this); 497 this.handleArrowFeatureCall((AFeatureCall) node.getFeatureCall()); 498 outAArrowPropertyCallExpressionTail(node); 499 } 500 501 /** 502 * @see org.andromda.translation.ocl.BaseTranslator#isOperationArgument(String) 503 */ 504 protected boolean isOperationArgument(String argument) 505 { 506 return super.isOperationArgument(this.getRootName(argument)); 507 } 508 509 /** 510 * Gets the root path name from the given <code>navigationalPath</code> (by trimming off any additional navigational 511 * path). 512 * 513 * @param navigationalPath the navigational property path (i.e. car.door) 514 * @return the root of the path name. 515 */ 516 private String getRootName(String navigationalPath) 517 { 518 return StringUtils.trimToEmpty(navigationalPath).replaceAll("\\..*", ""); 519 } 520 521 /** 522 * Gets the tail of the navigational path (that is it removes the root from the path and returns the tail). 523 * 524 * @param navigationalPath the navigational property path (i.e. car.door) 525 * @return the tail of the path name. 526 */ 527 private String getPathTail(String navigationalPath) 528 { 529 final int dotIndex = navigationalPath.indexOf('.'); 530 return dotIndex != -1 ? navigationalPath.substring(dotIndex + 1, navigationalPath.length()) : navigationalPath; 531 } 532 533 /** 534 * TODO: improve implementation to reduce the code duplication (avoid having two write statements) 535 * @param node 536 */ 537 public void caseAFeaturePrimaryExpression(AFeaturePrimaryExpression node) 538 { 539 inAFeaturePrimaryExpression(node); 540 if (node.getPathName() != null) 541 { 542 final String variableName = ((APathName) node.getPathName()).getName().getText(); 543 final String variableValue = getDeclaredLetVariableValue(variableName); 544 final boolean isDeclaredAsLetVariable = (variableValue != null); 545 String featureExpression = TranslationUtils.deleteWhitespace(node); 546 if (isDeclaredAsLetVariable) 547 { 548 write(variableValue); 549 } else if (node.getFeatureCallParameters() == null || OCLPatterns.isOperation(featureExpression)) 550 { 551 APropertyCallExpression expression = (APropertyCallExpression) node.parent(); 552 String expressionAsString = ConcreteSyntaxUtils.getPrimaryExpression(expression); 553 // remove any references to 'self.' as we write 554 expressionAsString = expressionAsString.replaceAll("self\\.", ""); 555 if (OCLFeatures.isSelf(expressionAsString)) 556 { 557 write(CONTEXT_ELEMENT_NAME); 558 } else if (StringUtils.isNotBlank(expressionAsString)) 559 { 560 boolean convertToBoolean = false; 561 if (node.parent().parent() instanceof AUnaryExpression) 562 { 563 AUnaryExpression unaryExpression = (AUnaryExpression) node.parent().parent(); 564 // we convert each unary not expression to boolean 565 convertToBoolean = unaryExpression.getUnaryOperator() instanceof ANotUnaryOperator; 566 if (convertToBoolean) 567 { 568 this.write(BOOLEAN_WRAP_PREFIX); 569 } 570 } 571 if (OCLFeatures.isOclIsKindOf(expressionAsString)) 572 { 573 this.write("object"); 574 this.handleOclIsKindOf(node.getFeatureCallParameters()); 575 } else if (OCLFeatures.isOclIsTypeOf(expressionAsString)) 576 { 577 this.write("object"); 578 this.handleOclIsTypeOf(node.getFeatureCallParameters()); 579 } else 580 { 581 // whether or not an introspector call is required 582 boolean introspectorCall = true; 583 String invokedObject = CONTEXT_ELEMENT_NAME; 584 // if we're in an arrow call we assume the invoked 585 // object is the object for which the arrow call applies 586 if (this.arrowPropertyCallStack.peek().equals(Boolean.TRUE)) 587 { 588 invokedObject = "object"; 589 } 590 if (this.isOperationArgument(expressionAsString)) 591 { 592 // - if the expression is an argument, then 593 // that becomes the invoked object 594 invokedObject = this.getRootName(expressionAsString); 595 expressionAsString = this.getPathTail(expressionAsString); 596 introspectorCall = !invokedObject.equals(expressionAsString); 597 } 598 if (introspectorCall) 599 { 600 write(OCL_INTROSPECTOR_INVOKE_PREFIX); 601 } 602 write(invokedObject); 603 if (introspectorCall) 604 { 605 write(",\""); 606 write(expressionAsString); 607 } 608 if (introspectorCall) 609 { 610 write("\")"); 611 } 612 if (convertToBoolean) 613 { 614 this.write(BOOLEAN_WRAP_SUFFIX); 615 } 616 } 617 if (this.requiresBooleanConversion) 618 { 619 this.write(BOOLEAN_WRAP_SUFFIX); 620 this.requiresBooleanConversion = false; 621 } 622 } 623 } else 624 { 625 node.getPathName().apply(this); 626 } 627 } 628 if (node.getIsMarkedPre() != null) 629 { 630 node.getIsMarkedPre().apply(this); 631 } 632 if (node.getQualifiers() != null) 633 { 634 // we use introspection when in an arrow, so passing 635 // feature name as a String without parentheses 636 if (this.arrowPropertyCallStack.peek().equals(Boolean.FALSE)) 637 { 638 node.getQualifiers().apply(this); 639 } 640 } 641 outAFeaturePrimaryExpression(node); 642 } 643 644 /** 645 * Handles an <strong>arrow </strong> feature call. Its expected that this <code>featureCall</code>'s parent is a 646 * AArrowPropertyCallExpressionTail. This is here because arrow feature calls must be handled differently than 647 * <code>dot<code> feature calls. 648 * 649 * @param featureCall the <strong>arrow</strong> <code>featureCall</code> to handle. 650 */ 651 public void handleArrowFeatureCall(AFeatureCall featureCall) 652 { 653 AFeatureCallParameters params = (AFeatureCallParameters) featureCall.getFeatureCallParameters(); 654 AActualParameterList list = null; 655 if (params != null) 656 { 657 list = (AActualParameterList) params.getActualParameterList(); 658 } 659 boolean arrow = this.arrowPropertyCallStack.peek().equals(Boolean.TRUE) && 660 StringUtils.isNotBlank(String.valueOf(list)); 661 { 662 newTranslationLayer(); 663 final String navigationalPath = ConcreteSyntaxUtils.getArrowFeatureCallResultNavigationalPath( 664 (APropertyCallExpression) featureCall.parent().parent()); 665 // if the result of an arrow feature (collection operation) has a 666 // navigational 667 // path, retrieve it and wrap the current expression with an OCL 668 // introspector call 669 boolean resultNavigationalPath = StringUtils.isNotBlank(navigationalPath); 670 if (resultNavigationalPath) 671 { 672 write(OCL_INTROSPECTOR_INVOKE_PREFIX); 673 } 674 write(OCL_TRANSLATOR_PACKAGE); 675 write(".OCLCollections."); 676 inAFeatureCall(featureCall); 677 if (featureCall.getPathName() != null) 678 { 679 featureCall.getPathName().apply(this); 680 } 681 String featureCallName = TranslationUtils.trimToEmpty(featureCall.getPathName()); 682 AFeatureCallParameters parameters = (AFeatureCallParameters) featureCall.getFeatureCallParameters(); 683 if (parameters != null) 684 { 685 if (parameters.getLParen() != null) 686 { 687 parameters.getLParen().apply(this); 688 } 689 mergeTranslationLayerBefore(); 690 AActualParameterList parameterList = (AActualParameterList) parameters.getActualParameterList(); 691 if (parameterList != null) 692 { 693 List expressions = parameterList.getCommaExpression(); 694 695 if (parameterList.getExpression() != null) 696 { 697 if (arrow) 698 { 699 write(","); 700 write(features.getProperty(featureCallName)); 701 write(" "); 702 if (OCLPredicateFeatures.isPredicateFeature(featureCallName)) 703 { 704 write(BOOLEAN_WRAP_PREFIX); 705 } 706 } 707 parameterList.getExpression().apply(this); 708 } 709 for (int ctr = 0; ctr < expressions.size(); ctr++) 710 { 711 Node expression = (Node) expressions.get(ctr); 712 if (expression != null) 713 { 714 write(","); 715 expression.apply(this); 716 } 717 } 718 if (parameterList.getExpression() != null) 719 { 720 if (OCLPredicateFeatures.isPredicateFeature(featureCallName)) 721 { 722 write(BOOLEAN_WRAP_SUFFIX); 723 } 724 if (arrow) 725 write(";}}"); 726 } 727 } 728 if (parameters.getRParen() != null) 729 { 730 parameters.getRParen().apply(this); 731 } 732 } 733 // now since we have a navigational path off of the 734 // result we need to write the path and close off 735 // the call to the OCL introspector. 736 if (resultNavigationalPath) 737 { 738 write(",\""); 739 write(navigationalPath); 740 write("\""); 741 write(")"); 742 } 743 this.outAFeatureCall(featureCall); 744 } 745 } 746 747 /** 748 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseALetExp(org.andromda.translation.ocl.node.ALetExp) 749 */ 750 public void caseALetExp(ALetExp node) 751 { 752 inALetExp(node); 753 if (node.getLet() != null) 754 { 755 node.getLet().apply(this); 756 } 757 if (node.getLetVariableDeclaration() != null) 758 { 759 node.getLetVariableDeclaration().apply(this); 760 } 761 if (node.getLetExpSub() != null) 762 { 763 node.getLetExpSub().apply(this); 764 } 765 outALetExp(node); 766 } 767 768 /** 769 * We are ready to store a new context of variables 770 * @param node 771 */ 772 public void inALetExp(ALetExp node) 773 { 774 newLetVariableContext(); 775 } 776 777 /** 778 * The variables are out of scope, we need to purge their context. 779 * @param node 780 */ 781 public void outALetExp(ALetExp node) 782 { 783 dropLetVariableContext(); 784 } 785 786 /** 787 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseAVariableDeclarationLetExpSub(org.andromda.translation.ocl.node.AVariableDeclarationLetExpSub) 788 */ 789 public void caseAVariableDeclarationLetExpSub(AVariableDeclarationLetExpSub node) 790 { 791 node.getComma().apply(this); 792 node.getLetVariableDeclaration().apply(this); 793 node.getLetExpSub().apply(this); 794 } 795 796 /** 797 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseALogicalExp(org.andromda.translation.ocl.node.ALogicalExp) 798 */ 799 public void caseALogicalExp(ALogicalExp node) 800 { 801 newTranslationLayer(); 802 if (node.getRelationalExpression() != null) 803 { 804 node.getRelationalExpression().apply(this); 805 } 806 Object[] tails = node.getLogicalExpressionTail().toArray(); 807 for (int ctr = 0; ctr < tails.length; ctr++) 808 { 809 ((ALogicalExpressionTail) tails[ctr]).apply(this); 810 } 811 mergeTranslationLayerAfter(); 812 } 813 814 /** 815 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseALogicalExpressionTail(org.andromda.translation.ocl.node.ALogicalExpressionTail) 816 */ 817 public void caseALogicalExpressionTail(ALogicalExpressionTail node) 818 { 819 node.getLogicalOperator().apply(this); 820 if (node.getLogicalOperator() instanceof AImpliesLogicalOperator) 821 { 822 prependToTranslationLayer("("); 823 } 824 if (node.getRelationalExpression() != null) 825 { 826 node.getRelationalExpression().apply(this); 827 } 828 if (node.getLogicalOperator() instanceof AImpliesLogicalOperator) 829 { 830 write(":true)"); 831 } 832 } 833 834 /** 835 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#caseARelationalExpressionTail(org.andromda.translation.ocl.node.ARelationalExpressionTail) 836 */ 837 public void caseARelationalExpressionTail(ARelationalExpressionTail node) 838 { 839 inARelationalExpressionTail(node); 840 841 newTranslationLayer(); 842 write(OCL_TRANSLATOR_PACKAGE); 843 write(".OCLExpressions."); 844 node.getRelationalOperator().apply(this); 845 write("("); 846 mergeTranslationLayerBefore(); 847 if (node.getAdditiveExpression() != null) 848 { 849 write(","); 850 node.getAdditiveExpression().apply(this); 851 } 852 write(")"); 853 outARelationalExpressionTail(node); 854 } 855 856 /** 857 * A flag indicating if the expression needs to be converted/wrapped in a Java Boolean instance. 858 */ 859 private boolean requiresBooleanConversion = false; 860 861 /** 862 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#inARelationalExpression(org.andromda.translation.ocl.node.ARelationalExpression) 863 */ 864 public void inARelationalExpression(ARelationalExpression node) 865 { 866 // in this block of code, we determine whether or not 867 // the next appended expression needs to be 868 // converted/wrapped by a Java Boolean 869 if (node.getRelationalExpressionTail() == null) 870 { 871 Object parent = node.parent(); 872 Object expression = null; 873 if (parent instanceof ALogicalExp) 874 { 875 List tails = ((ALogicalExp) parent).getLogicalExpressionTail(); 876 if (tails != null && !tails.isEmpty()) 877 { 878 expression = tails.get(0); 879 // if it's an AND or OR expression set the expression 880 // to the node 881 if (OCLPatterns.isAndOrOrExpression(expression)) 882 { 883 expression = node; 884 } 885 } 886 } else if (parent instanceof ALogicalExpressionTail) 887 { 888 expression = node; 889 } 890 requiresBooleanConversion = expression != null 891 && OCLPatterns.isNavigationalPath(expression) 892 && !OCLPatterns.isOperation(node); 893 if (this.requiresBooleanConversion) 894 { 895 this.write(BOOLEAN_WRAP_PREFIX); 896 } 897 } 898 newTranslationLayer(); 899 } 900 901 /** 902 * @see org.andromda.translation.ocl.analysis.DepthFirstAdapter#outARelationalExpression(org.andromda.translation.ocl.node.ARelationalExpression) 903 */ 904 public void outARelationalExpression(ARelationalExpression node) 905 { 906 mergeTranslationLayerAfter(); 907 } 908 909 /** 910 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTName(org.andromda.translation.ocl.node.TName) 911 */ 912 public void caseTName(TName node) 913 { 914 write(node.getText()); 915 } 916 917 /** 918 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTAnd(org.andromda.translation.ocl.node.TAnd) 919 */ 920 public void caseTAnd(TAnd tAnd) 921 { 922 write("&&"); 923 } 924 925 /** 926 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTOr(org.andromda.translation.ocl.node.TOr) 927 */ 928 public void caseTOr(TOr tOr) 929 { 930 write("||"); 931 } 932 933 /** 934 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTXor(org.andromda.translation.ocl.node.TXor) 935 */ 936 public void caseTXor(TXor tXor) 937 { 938 write("^"); 939 } 940 941 /** 942 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTImplies(org.andromda.translation.ocl.node.TImplies) 943 */ 944 public void caseTImplies(TImplies tImplies) 945 { 946 // convert any non boolean's to boolean 947 this.prependToTranslationLayer(BOOLEAN_WRAP_PREFIX); 948 this.appendToTranslationLayer(BOOLEAN_WRAP_SUFFIX); 949 write("?"); 950 } 951 952 /** 953 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTNot(org.andromda.translation.ocl.node.TNot) 954 */ 955 public void caseTNot(TNot tNot) 956 { 957 write("!"); 958 } 959 960 /** 961 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTPlus(org.andromda.translation.ocl.node.TPlus) 962 */ 963 public void caseTPlus(TPlus tPlus) 964 { 965 write("+"); 966 } 967 968 /** 969 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTMinus(org.andromda.translation.ocl.node.TMinus) 970 */ 971 public void caseTMinus(TMinus tMinus) 972 { 973 write("-"); 974 } 975 976 /** 977 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTMult(org.andromda.translation.ocl.node.TMult) 978 */ 979 public void caseTMult(TMult tMult) 980 { 981 write("*"); 982 } 983 984 /** 985 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTDiv(org.andromda.translation.ocl.node.TDiv) 986 */ 987 public void caseTDiv(TDiv tDiv) 988 { 989 write("/"); 990 } 991 992 /** 993 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTEqual(org.andromda.translation.ocl.node.TEqual) 994 */ 995 public void caseTEqual(TEqual tEqual) 996 { 997 write("equal"); 998 } 999 1000 /** 1001 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTNotEqual(org.andromda.translation.ocl.node.TNotEqual) 1002 */ 1003 public void caseTNotEqual(TNotEqual tNotEqual) 1004 { 1005 write("notEqual"); 1006 } 1007 1008 /** 1009 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLt(org.andromda.translation.ocl.node.TLt) 1010 */ 1011 public void caseTLt(TLt tLt) 1012 { 1013 write("less"); 1014 } 1015 1016 /** 1017 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLteq(org.andromda.translation.ocl.node.TLteq) 1018 */ 1019 public void caseTLteq(TLteq tLteq) 1020 { 1021 write("lessOrEqual"); 1022 } 1023 1024 /** 1025 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTGt(org.andromda.translation.ocl.node.TGt) 1026 */ 1027 public void caseTGt(TGt tGt) 1028 { 1029 write("greater"); 1030 } 1031 1032 /** 1033 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTGteq(org.andromda.translation.ocl.node.TGteq) 1034 */ 1035 public void caseTGteq(TGteq tGteq) 1036 { 1037 write("greaterOrEqual"); 1038 } 1039 1040 /** 1041 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTInv(org.andromda.translation.ocl.node.TInv) 1042 */ 1043 public void caseTInv(TInv tInv) 1044 { 1045 } 1046 1047 /** 1048 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTDef(org.andromda.translation.ocl.node.TDef) 1049 */ 1050 public void caseTDef(TDef tDef) 1051 { 1052 } 1053 1054 /** 1055 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLet(org.andromda.translation.ocl.node.TLet) 1056 */ 1057 public void caseTLet(TLet tLet) 1058 { 1059 } 1060 1061 /** 1062 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTColon(org.andromda.translation.ocl.node.TColon) 1063 */ 1064 public void caseTColon(TColon tColon) 1065 { 1066 } 1067 1068 /** 1069 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLBrace(org.andromda.translation.ocl.node.TLBrace) 1070 */ 1071 public void caseTLBrace(TLBrace tlBrace) 1072 { 1073 write("{"); 1074 } 1075 1076 /** 1077 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLBracket(org.andromda.translation.ocl.node.TLBracket) 1078 */ 1079 public void caseTLBracket(TLBracket tlBracket) 1080 { 1081 write("["); 1082 } 1083 1084 /** 1085 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTLParen(org.andromda.translation.ocl.node.TLParen) 1086 */ 1087 public void caseTLParen(TLParen tlParen) 1088 { 1089 write("("); 1090 } 1091 1092 /** 1093 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTRBrace(org.andromda.translation.ocl.node.TRBrace) 1094 */ 1095 public void caseTRBrace(TRBrace trBrace) 1096 { 1097 write("}"); 1098 } 1099 1100 /** 1101 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTRBracket(org.andromda.translation.ocl.node.TRBracket) 1102 */ 1103 public void caseTRBracket(TRBracket trBracket) 1104 { 1105 write("]"); 1106 } 1107 1108 /** 1109 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTRParen(org.andromda.translation.ocl.node.TRParen) 1110 */ 1111 public void caseTRParen(TRParen trParen) 1112 { 1113 write(")"); 1114 } 1115 1116 /** 1117 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTContext(org.andromda.translation.ocl.node.TContext) 1118 */ 1119 public void caseTContext(TContext tContext) 1120 { 1121 } 1122 1123 /** 1124 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTBoolean(org.andromda.translation.ocl.node.TBoolean) 1125 */ 1126 public void caseTBoolean(TBoolean tBoolean) 1127 { 1128 write(tBoolean.getText()); 1129 } 1130 1131 /** 1132 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTApostrophe(org.andromda.translation.ocl.node.TApostrophe) 1133 */ 1134 public void caseTApostrophe(TApostrophe tApostrophe) 1135 { 1136 write("\'"); 1137 } 1138 1139 /** 1140 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTBlank(org.andromda.translation.ocl.node.TBlank) 1141 */ 1142 public void caseTBlank(TBlank tBlank) 1143 { 1144 write(" "); 1145 } 1146 1147 /** 1148 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTCollection(org.andromda.translation.ocl.node.TCollection) 1149 */ 1150 public void caseTCollection(TCollection tCollection) 1151 { 1152 write("java.util.Collection "); 1153 } 1154 1155 /** 1156 * @param tSingleLineComment 1157 */ 1158 public void caseTComment(TSingleLineComment tSingleLineComment) 1159 { 1160 write("// "); 1161 } 1162 1163 /** 1164 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTEndif(org.andromda.translation.ocl.node.TEndif) 1165 */ 1166 public void caseTEndif(TEndif tEndif) 1167 { 1168 } 1169 1170 /** 1171 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTAttr(org.andromda.translation.ocl.node.TAttr) 1172 */ 1173 public void caseTAttr(TAttr tAttr) 1174 { 1175 } 1176 1177 /** 1178 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTBag(org.andromda.translation.ocl.node.TBag) 1179 */ 1180 public void caseTBag(TBag tBag) 1181 { 1182 } 1183 1184 /** 1185 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTBar(org.andromda.translation.ocl.node.TBar) 1186 */ 1187 public void caseTBar(TBar tBar) 1188 { 1189 } 1190 1191 /** 1192 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTBody(org.andromda.translation.ocl.node.TBody) 1193 */ 1194 public void caseTBody(TBody tBody) 1195 { 1196 } 1197 1198 /** 1199 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTCommercialAt(org.andromda.translation.ocl.node.TCommercialAt) 1200 */ 1201 public void caseTCommercialAt(TCommercialAt tCommercialAt) 1202 { 1203 } 1204 1205 /** 1206 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTDerive(org.andromda.translation.ocl.node.TDerive) 1207 */ 1208 public void caseTDerive(TDerive tDerive) 1209 { 1210 } 1211 1212 /** 1213 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTEndpackage(org.andromda.translation.ocl.node.TEndpackage) 1214 */ 1215 public void caseTEndpackage(TEndpackage tEndpackage) 1216 { 1217 } 1218 1219 /** 1220 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTEnum(org.andromda.translation.ocl.node.TEnum) 1221 */ 1222 public void caseTEnum(TEnum tEnum) 1223 { 1224 } 1225 1226 /** 1227 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTIn(org.andromda.translation.ocl.node.TIn) 1228 */ 1229 public void caseTIn(TIn tIn) 1230 { 1231 } 1232 1233 /** 1234 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTInit(org.andromda.translation.ocl.node.TInit) 1235 */ 1236 public void caseTInit(TInit tInit) 1237 { 1238 } 1239 1240 /** 1241 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTInt(org.andromda.translation.ocl.node.TInt) 1242 */ 1243 public void caseTInt(TInt tInt) 1244 { 1245 write(tInt.getText()); 1246 } 1247 1248 /** 1249 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTIsSentOperator(org.andromda.translation.ocl.node.TIsSentOperator) 1250 */ 1251 public void caseTIsSentOperator(TIsSentOperator tIsSentOperator) 1252 { 1253 } 1254 1255 /** 1256 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTMessageOperator(org.andromda.translation.ocl.node.TMessageOperator) 1257 */ 1258 public void caseTMessageOperator(TMessageOperator tMessageOperator) 1259 { 1260 } 1261 1262 /** 1263 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTNewLine(org.andromda.translation.ocl.node.TNewLine) 1264 */ 1265 public void caseTNewLine(TNewLine tNewLine) 1266 { 1267 } 1268 1269 /** 1270 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTOper(org.andromda.translation.ocl.node.TOper) 1271 */ 1272 public void caseTOper(TOper tOper) 1273 { 1274 } 1275 1276 /** 1277 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTOrderedset(org.andromda.translation.ocl.node.TOrderedset) 1278 */ 1279 public void caseTOrderedset(TOrderedset tOrderedset) 1280 { 1281 } 1282 1283 /** 1284 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTPackage(org.andromda.translation.ocl.node.TPackage) 1285 */ 1286 public void caseTPackage(TPackage tPackage) 1287 { 1288 } 1289 1290 /** 1291 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTPost(org.andromda.translation.ocl.node.TPost) 1292 */ 1293 public void caseTPost(TPost tPost) 1294 { 1295 } 1296 1297 /** 1298 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTPre(org.andromda.translation.ocl.node.TPre) 1299 */ 1300 public void caseTPre(TPre tPre) 1301 { 1302 } 1303 1304 /** 1305 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTArrow(org.andromda.translation.ocl.node.TArrow) 1306 */ 1307 public void caseTArrow(TArrow tArrow) 1308 { 1309 } 1310 1311 /** 1312 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTIf(org.andromda.translation.ocl.node.TIf) 1313 */ 1314 public void caseTIf(TIf tIf) 1315 { 1316 write("if"); 1317 } 1318 1319 /** 1320 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTElse(org.andromda.translation.ocl.node.TElse) 1321 */ 1322 public void caseTElse(TElse tElse) 1323 { 1324 write("else"); 1325 } 1326 1327 /** 1328 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTThen(org.andromda.translation.ocl.node.TThen) 1329 */ 1330 public void caseTThen(TThen tThen) 1331 { 1332 } 1333 1334 /** 1335 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTRange(org.andromda.translation.ocl.node.TRange) 1336 */ 1337 public void caseTRange(TRange tRange) 1338 { 1339 } 1340 1341 /** 1342 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTReal(org.andromda.translation.ocl.node.TReal) 1343 */ 1344 public void caseTReal(TReal tReal) 1345 { 1346 write(tReal.getText()); 1347 } 1348 1349 /** 1350 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTComma(org.andromda.translation.ocl.node.TComma) 1351 */ 1352 public void caseTComma(TComma tComma) 1353 { 1354 write(", "); 1355 } 1356 1357 /** 1358 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTDot(org.andromda.translation.ocl.node.TDot) 1359 */ 1360 public void caseTDot(TDot tDot) 1361 { 1362 write("."); 1363 } 1364 1365 /** 1366 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTSemicolon(org.andromda.translation.ocl.node.TSemicolon) 1367 */ 1368 public void caseTSemicolon(TSemicolon tSemicolon) 1369 { 1370 } 1371 1372 /** 1373 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTUnknown(org.andromda.translation.ocl.node.TUnknown) 1374 */ 1375 public void caseTUnknown(TUnknown tUnknown) 1376 { 1377 } 1378 1379 /** 1380 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTScopeOperator(org.andromda.translation.ocl.node.TScopeOperator) 1381 */ 1382 public void caseTScopeOperator(TScopeOperator tScopeOperator) 1383 { 1384 write("."); 1385 } 1386 1387 /** 1388 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTSequence(org.andromda.translation.ocl.node.TSequence) 1389 */ 1390 public void caseTSequence(TSequence tSequence) 1391 { 1392 } 1393 1394 /** 1395 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTSet(org.andromda.translation.ocl.node.TSet) 1396 */ 1397 public void caseTSet(TSet tSet) 1398 { 1399 } 1400 1401 /** 1402 * @param tStringLit 1403 * TODO: this method very naively replaces every single quote by a double quote, this should be updated 1404 */ 1405 public void caseTStringLit(TStringLit tStringLit) 1406 { 1407 final StringBuffer buffer = new StringBuffer(tStringLit.getText().replace('\'', '\"')); 1408 write(buffer); 1409 } 1410 1411 /** 1412 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTTab(org.andromda.translation.ocl.node.TTab) 1413 */ 1414 public void caseTTab(TTab tTab) 1415 { 1416 } 1417 1418 /** 1419 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTTuple(org.andromda.translation.ocl.node.TTuple) 1420 */ 1421 public void caseTTuple(TTuple tTuple) 1422 { 1423 } 1424 1425 /** 1426 * @see org.andromda.translation.ocl.analysis.AnalysisAdapter#caseTTupletype(org.andromda.translation.ocl.node.TTupletype) 1427 */ 1428 public void caseTTupletype(TTupletype tTupletype) 1429 { 1430 } 1431 1432 private final Stack translationLayers = new Stack(); 1433 1434 /** 1435 * Contains Boolean.TRUE on the top when the most recent property call was an arrow property call, contains 1436 * Boolean.FALSE otherwise. 1437 */ 1438 private final Stack arrowPropertyCallStack = new Stack(); 1439 1440 /** 1441 * This stack contains elements implementing the Map interface. For each definition of variables a new Map element 1442 * will be pushed onto the stack. This element contains the variables defined in the definition. 1443 * <p/> 1444 * The keys and values contained in the Map are the names of the variables only (String instances). 1445 */ 1446 private final Stack letVariableStack = new Stack(); 1447 1448 private void write(Object object) 1449 { 1450 appendToTranslationLayer(String.valueOf(object)); 1451 } 1452 1453 private StringBuffer newTranslationLayer() 1454 { 1455 return (StringBuffer) translationLayers.push(new StringBuffer()); 1456 } 1457 1458 private StringBuffer appendToTranslationLayer(Object appendix) 1459 { 1460 return ((StringBuffer) translationLayers.peek()).append(appendix); 1461 } 1462 1463 private StringBuffer prependToTranslationLayer(Object appendix) 1464 { 1465 return ((StringBuffer) translationLayers.peek()).insert(0, appendix); 1466 } 1467 1468 private StringBuffer mergeTranslationLayerAfter() 1469 { 1470 StringBuffer newTop = null; 1471 1472 if (translationLayers.size() > 1) 1473 { 1474 newTop = appendToTranslationLayer(translationLayers.pop()); 1475 } 1476 1477 return newTop; 1478 } 1479 1480 private StringBuffer mergeTranslationLayerBefore() 1481 { 1482 StringBuffer newTop = null; 1483 1484 if (translationLayers.size() > 1) 1485 { 1486 newTop = prependToTranslationLayer(translationLayers.pop()); 1487 } 1488 1489 return newTop; 1490 } 1491 1492 private StringBuffer mergeTranslationLayers() 1493 { 1494 while (mergeTranslationLayerAfter() != null) ; 1495 return (StringBuffer) translationLayers.peek(); 1496 } 1497 1498 private String getDeclaredLetVariableValue(String variableName) 1499 { 1500 for (final Iterator iterator = letVariableStack.iterator(); iterator.hasNext();) 1501 { 1502 Map variableMap = (Map) iterator.next(); 1503 if (variableMap.containsKey(variableName)) 1504 { 1505 return (String) variableMap.get(variableName); 1506 } 1507 } 1508 return null; 1509 } 1510 1511 private void newLetVariableContext() 1512 { 1513 letVariableStack.push(new HashMap(4)); 1514 } 1515 1516 private void dropLetVariableContext() 1517 { 1518 if (!letVariableStack.isEmpty()) 1519 letVariableStack.pop(); 1520 } 1521 1522 private void addLetVariableToContext(String variableName, String variableValue) 1523 { 1524 ((Map) letVariableStack.peek()).put(variableName, variableValue); 1525 } 1526 1527 /** 1528 * Gets the current context element as a {@link org.andromda.uml.metafacades.ModelElementFacade}. 1529 * 1530 * @return the context element as a model element facade 1531 */ 1532 private ModelElementFacade getModelElement() 1533 { 1534 return (ModelElementFacade) this.getContextElement(); 1535 } 1536 1537 /** 1538 * 1539 */ 1540 public ValidationJavaTranslator() 1541 { 1542 arrowPropertyCallStack.push(Boolean.FALSE); 1543 } 1544 1545 /** 1546 * The name of the context element within the translated expression. 1547 */ 1548 private static final String CONTEXT_ELEMENT_NAME = "contextElement"; 1549 1550 /** 1551 * The prefix for calling the OCLIntrospector to invoke a property or method on an element. 1552 */ 1553 private static final String OCL_INTROSPECTOR_INVOKE_PREFIX = OCL_TRANSLATOR_PACKAGE + ".OCLIntrospector.invoke("; 1554 1555 /** 1556 * The prefix for converting expressions to boolean expressions 1557 */ 1558 private static final String BOOLEAN_WRAP_PREFIX = "Boolean.valueOf(String.valueOf("; 1559 1560 /** 1561 * The suffix for converting expressions to boolean expressions; 1562 */ 1563 private static final String BOOLEAN_WRAP_SUFFIX = ")).booleanValue()"; 1564 1565 /** 1566 * We need to wrap every expression with a converter so that any expressions that return just objects are converted 1567 * to boolean values. 1568 * 1569 * @see org.andromda.translation.ocl.BaseTranslator#postProcess() 1570 */ 1571 @Override 1572 public void postProcess() 1573 { 1574 this.getExpression().insertInTranslatedExpression(0, OCL_TRANSLATOR_PACKAGE + ".OCLResultEnsurer.ensure("); 1575 this.getExpression().insertInTranslatedExpression(0, "boolean constraintValid = "); 1576 this.getExpression().insertInTranslatedExpression(0, 1577 "final Object " + CONTEXT_ELEMENT_NAME + " = this; "); 1578 this.getExpression().appendToTranslatedExpression(");"); 1579 } 1580}