001package org.apache.maven.tools.plugin.generator; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.io.OutputStreamWriter; 025import java.io.Writer; 026import java.net.URI; 027import java.util.LinkedHashMap; 028import java.util.LinkedHashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033import org.apache.maven.plugin.descriptor.MojoDescriptor; 034import org.apache.maven.plugin.descriptor.Parameter; 035import org.apache.maven.plugin.descriptor.PluginDescriptor; 036import org.apache.maven.plugin.descriptor.Requirement; 037import org.apache.maven.project.MavenProject; 038import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 039import org.apache.maven.tools.plugin.PluginToolsRequest; 040import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator; 041import org.apache.maven.tools.plugin.util.PluginUtils; 042import org.codehaus.plexus.util.StringUtils; 043import org.codehaus.plexus.util.io.CachingOutputStream; 044import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; 045import org.codehaus.plexus.util.xml.XMLWriter; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049import static java.nio.charset.StandardCharsets.UTF_8; 050 051/** 052 * Serializes 053 * <ol> 054 * <li>a standard <a href="/ref/current/maven-plugin-api/plugin.html">Maven Plugin Descriptor XML file</a></li> 055 * <li>a descriptor containing a limited set of attributes for {@link PluginHelpGenerator}</li> 056 * <li>an enhanced descriptor containing HTML values for some elements (instead of plain text as for the other two) 057 * for {@link PluginXdocGenerator}</li> 058 * </ol> 059 * from a given in-memory descriptor. The in-memory descriptor acting as source is supposed to contain XHTML values 060 * for description elements. 061 * 062 */ 063public class PluginDescriptorFilesGenerator 064 implements Generator 065{ 066 private static final Logger LOG = LoggerFactory.getLogger( PluginDescriptorFilesGenerator.class ); 067 068 /** 069 * The type of the plugin descriptor file 070 */ 071 enum DescriptorType 072 { 073 STANDARD, 074 LIMITED_FOR_HELP_MOJO, 075 XHTML 076 } 077 078 @Override 079 public void execute( File destinationDirectory, PluginToolsRequest request ) 080 throws GeneratorException 081 { 082 try 083 { 084 // write standard plugin.xml descriptor 085 File f = new File( destinationDirectory, "plugin.xml" ); 086 writeDescriptor( f, request, DescriptorType.STANDARD ); 087 088 // write plugin-help.xml help-descriptor (containing only a limited set of attributes) 089 MavenProject mavenProject = request.getProject(); 090 f = new File( destinationDirectory, 091 PluginHelpGenerator.getPluginHelpPath( mavenProject ) ); 092 writeDescriptor( f, request, DescriptorType.LIMITED_FOR_HELP_MOJO ); 093 094 // write enhanced plugin-enhanced.xml descriptor (containing some XHTML values) 095 f = getEnhancedDescriptorFilePath( mavenProject ); 096 writeDescriptor( f, request, DescriptorType.XHTML ); 097 } 098 catch ( IOException e ) 099 { 100 throw new GeneratorException( e.getMessage(), e ); 101 } 102 } 103 104 public static File getEnhancedDescriptorFilePath( MavenProject project ) 105 { 106 return new File( project.getBuild().getDirectory(), "plugin-enhanced.xml" ); 107 } 108 109 private String getVersion() 110 { 111 Package p = this.getClass().getPackage(); 112 String version = ( p == null ) ? null : p.getSpecificationVersion(); 113 return ( version == null ) ? "SNAPSHOT" : version; 114 } 115 116 public void writeDescriptor( File destinationFile, PluginToolsRequest request, DescriptorType type ) 117 throws IOException 118 { 119 PluginDescriptor pluginDescriptor = request.getPluginDescriptor(); 120 121 if ( !destinationFile.getParentFile().exists() ) 122 { 123 destinationFile.getParentFile().mkdirs(); 124 } 125 126 try ( Writer writer = new OutputStreamWriter( new CachingOutputStream( destinationFile ), UTF_8 ) ) 127 { 128 XMLWriter w = new PrettyPrintXMLWriter( writer, UTF_8.name(), null ); 129 130 final String additionalInfo; 131 switch ( type ) 132 { 133 case LIMITED_FOR_HELP_MOJO: 134 additionalInfo = " (for help'mojo with additional elements)"; 135 break; 136 case XHTML: 137 additionalInfo = " (enhanced XHTML version with additional elements (used for plugin:report))"; 138 break; 139 default: 140 additionalInfo = ""; 141 break; 142 } 143 w.writeMarkup( "\n<!-- Generated by maven-plugin-tools " + getVersion() 144 + additionalInfo + "-->\n\n" ); 145 146 w.startElement( "plugin" ); 147 148 GeneratorUtils.element( w, "name", pluginDescriptor.getName() ); 149 150 GeneratorUtils.element( w, "description", pluginDescriptor.getDescription() ); 151 152 GeneratorUtils.element( w, "groupId", pluginDescriptor.getGroupId() ); 153 154 GeneratorUtils.element( w, "artifactId", pluginDescriptor.getArtifactId() ); 155 156 GeneratorUtils.element( w, "version", pluginDescriptor.getVersion() ); 157 158 GeneratorUtils.element( w, "goalPrefix", pluginDescriptor.getGoalPrefix() ); 159 160 if ( type != DescriptorType.LIMITED_FOR_HELP_MOJO ) 161 { 162 GeneratorUtils.element( w, "isolatedRealm", String.valueOf( pluginDescriptor.isIsolatedRealm() ) ); 163 164 GeneratorUtils.element( w, "inheritedByDefault", 165 String.valueOf( pluginDescriptor.isInheritedByDefault() ) ); 166 } 167 168 w.startElement( "mojos" ); 169 170 final JavadocLinkGenerator javadocLinkGenerator; 171 if ( request.getInternalJavadocBaseUrl() != null 172 || ( request.getExternalJavadocBaseUrls() != null 173 && !request.getExternalJavadocBaseUrls().isEmpty() ) ) 174 { 175 javadocLinkGenerator = new JavadocLinkGenerator( request.getInternalJavadocBaseUrl(), 176 request.getInternalJavadocVersion(), 177 request.getExternalJavadocBaseUrls(), 178 request.getSettings() ); 179 } 180 else 181 { 182 javadocLinkGenerator = null; 183 } 184 if ( pluginDescriptor.getMojos() != null ) 185 { 186 List<MojoDescriptor> descriptors = pluginDescriptor.getMojos(); 187 188 PluginUtils.sortMojos( descriptors ); 189 190 for ( MojoDescriptor descriptor : descriptors ) 191 { 192 processMojoDescriptor( descriptor, w, type, javadocLinkGenerator ); 193 } 194 } 195 196 w.endElement(); 197 198 if ( type != DescriptorType.LIMITED_FOR_HELP_MOJO ) 199 { 200 GeneratorUtils.writeDependencies( w, pluginDescriptor ); 201 } 202 203 w.endElement(); 204 205 writer.flush(); 206 207 } 208 } 209 210 /** 211 * 212 * @param type 213 * @param containsXhtmlValue 214 * @param text 215 * @return the normalized text value (i.e. potentially converted to XHTML) 216 */ 217 private static String getTextValue( DescriptorType type, boolean containsXhtmlValue, String text ) 218 { 219 final String xhtmlText; 220 if ( !containsXhtmlValue ) // text comes from legacy extractor 221 { 222 xhtmlText = GeneratorUtils.makeHtmlValid( text ); 223 } 224 else 225 { 226 xhtmlText = text; 227 } 228 if ( type != DescriptorType.XHTML ) 229 { 230 return new HtmlToPlainTextConverter().convert( text ); 231 } 232 else 233 { 234 return xhtmlText; 235 } 236 } 237 238 @SuppressWarnings( "deprecation" ) 239 protected void processMojoDescriptor( MojoDescriptor mojoDescriptor, XMLWriter w, DescriptorType type, 240 JavadocLinkGenerator javadocLinkGenerator ) 241 { 242 boolean containsXhtmlTextValues = mojoDescriptor instanceof ExtendedMojoDescriptor 243 && ( (ExtendedMojoDescriptor) mojoDescriptor ).containsXhtmlTextValues(); 244 245 w.startElement( "mojo" ); 246 247 // ---------------------------------------------------------------------- 248 // 249 // ---------------------------------------------------------------------- 250 251 w.startElement( "goal" ); 252 w.writeText( mojoDescriptor.getGoal() ); 253 w.endElement(); 254 255 // ---------------------------------------------------------------------- 256 // 257 // ---------------------------------------------------------------------- 258 259 String description = mojoDescriptor.getDescription(); 260 261 if ( StringUtils.isNotEmpty( description ) ) 262 { 263 w.startElement( "description" ); 264 w.writeText( getTextValue( type, containsXhtmlTextValues, mojoDescriptor.getDescription() ) ); 265 w.endElement(); 266 } 267 268 // ---------------------------------------------------------------------- 269 // 270 // ---------------------------------------------------------------------- 271 272 if ( StringUtils.isNotEmpty( mojoDescriptor.isDependencyResolutionRequired() ) ) 273 { 274 GeneratorUtils.element( w, "requiresDependencyResolution", 275 mojoDescriptor.isDependencyResolutionRequired() ); 276 } 277 278 // ---------------------------------------------------------------------- 279 // 280 // ---------------------------------------------------------------------- 281 282 GeneratorUtils.element( w, "requiresDirectInvocation", 283 String.valueOf( mojoDescriptor.isDirectInvocationOnly() ) ); 284 285 // ---------------------------------------------------------------------- 286 // 287 // ---------------------------------------------------------------------- 288 289 GeneratorUtils.element( w, "requiresProject", String.valueOf( mojoDescriptor.isProjectRequired() ) ); 290 291 // ---------------------------------------------------------------------- 292 // 293 // ---------------------------------------------------------------------- 294 295 GeneratorUtils.element( w, "requiresReports", String.valueOf( mojoDescriptor.isRequiresReports() ) ); 296 297 // ---------------------------------------------------------------------- 298 // 299 // ---------------------------------------------------------------------- 300 301 GeneratorUtils.element( w, "aggregator", String.valueOf( mojoDescriptor.isAggregator() ) ); 302 303 // ---------------------------------------------------------------------- 304 // 305 // ---------------------------------------------------------------------- 306 307 GeneratorUtils.element( w, "requiresOnline", String.valueOf( mojoDescriptor.isOnlineRequired() ) ); 308 309 // ---------------------------------------------------------------------- 310 // 311 // ---------------------------------------------------------------------- 312 313 GeneratorUtils.element( w, "inheritedByDefault", String.valueOf( mojoDescriptor.isInheritedByDefault() ) ); 314 315 // ---------------------------------------------------------------------- 316 // 317 // ---------------------------------------------------------------------- 318 319 if ( StringUtils.isNotEmpty( mojoDescriptor.getPhase() ) ) 320 { 321 GeneratorUtils.element( w, "phase", mojoDescriptor.getPhase() ); 322 } 323 324 // ---------------------------------------------------------------------- 325 // 326 // ---------------------------------------------------------------------- 327 328 if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) ) 329 { 330 GeneratorUtils.element( w, "executePhase", mojoDescriptor.getExecutePhase() ); 331 } 332 333 if ( StringUtils.isNotEmpty( mojoDescriptor.getExecuteGoal() ) ) 334 { 335 GeneratorUtils.element( w, "executeGoal", mojoDescriptor.getExecuteGoal() ); 336 } 337 338 if ( StringUtils.isNotEmpty( mojoDescriptor.getExecuteLifecycle() ) ) 339 { 340 GeneratorUtils.element( w, "executeLifecycle", mojoDescriptor.getExecuteLifecycle() ); 341 } 342 343 // ---------------------------------------------------------------------- 344 // 345 // ---------------------------------------------------------------------- 346 347 w.startElement( "implementation" ); 348 w.writeText( mojoDescriptor.getImplementation() ); 349 w.endElement(); 350 351 // ---------------------------------------------------------------------- 352 // 353 // ---------------------------------------------------------------------- 354 355 w.startElement( "language" ); 356 w.writeText( mojoDescriptor.getLanguage() ); 357 w.endElement(); 358 359 // ---------------------------------------------------------------------- 360 // 361 // ---------------------------------------------------------------------- 362 363 if ( StringUtils.isNotEmpty( mojoDescriptor.getComponentConfigurator() ) ) 364 { 365 w.startElement( "configurator" ); 366 w.writeText( mojoDescriptor.getComponentConfigurator() ); 367 w.endElement(); 368 } 369 370 // ---------------------------------------------------------------------- 371 // 372 // ---------------------------------------------------------------------- 373 374 if ( StringUtils.isNotEmpty( mojoDescriptor.getComponentComposer() ) ) 375 { 376 w.startElement( "composer" ); 377 w.writeText( mojoDescriptor.getComponentComposer() ); 378 w.endElement(); 379 } 380 381 // ---------------------------------------------------------------------- 382 // 383 // ---------------------------------------------------------------------- 384 385 w.startElement( "instantiationStrategy" ); 386 w.writeText( mojoDescriptor.getInstantiationStrategy() ); 387 w.endElement(); 388 389 // ---------------------------------------------------------------------- 390 // Strategy for handling repeated reference to mojo in 391 // the calculated (decorated, resolved) execution stack 392 // ---------------------------------------------------------------------- 393 w.startElement( "executionStrategy" ); 394 w.writeText( mojoDescriptor.getExecutionStrategy() ); 395 w.endElement(); 396 397 // ---------------------------------------------------------------------- 398 // 399 // ---------------------------------------------------------------------- 400 401 if ( mojoDescriptor.getSince() != null ) 402 { 403 w.startElement( "since" ); 404 405 if ( StringUtils.isEmpty( mojoDescriptor.getSince() ) ) 406 { 407 w.writeText( "No version given" ); 408 } 409 else 410 { 411 w.writeText( mojoDescriptor.getSince() ); 412 } 413 414 w.endElement(); 415 } 416 417 // ---------------------------------------------------------------------- 418 // 419 // ---------------------------------------------------------------------- 420 421 if ( mojoDescriptor.getDeprecated() != null ) 422 { 423 w.startElement( "deprecated" ); 424 425 if ( StringUtils.isEmpty( mojoDescriptor.getDeprecated() ) ) 426 { 427 w.writeText( "No reason given" ); 428 } 429 else 430 { 431 w.writeText( getTextValue( type, containsXhtmlTextValues, mojoDescriptor.getDeprecated() ) ); 432 } 433 434 w.endElement(); 435 } 436 437 // ---------------------------------------------------------------------- 438 // Extended (3.0) descriptor 439 // ---------------------------------------------------------------------- 440 441 if ( mojoDescriptor instanceof ExtendedMojoDescriptor ) 442 { 443 ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor; 444 if ( extendedMojoDescriptor.getDependencyCollectionRequired() != null ) 445 { 446 GeneratorUtils.element( w, "requiresDependencyCollection", 447 extendedMojoDescriptor.getDependencyCollectionRequired() ); 448 } 449 450 GeneratorUtils.element( w, "threadSafe", String.valueOf( extendedMojoDescriptor.isThreadSafe() ) ); 451 } 452 453 // ---------------------------------------------------------------------- 454 // Parameters 455 // ---------------------------------------------------------------------- 456 457 List<Parameter> parameters = mojoDescriptor.getParameters(); 458 459 w.startElement( "parameters" ); 460 461 Map<String, Requirement> requirements = new LinkedHashMap<>(); 462 463 Set<Parameter> configuration = new LinkedHashSet<>(); 464 465 if ( parameters != null ) 466 { 467 if ( type == DescriptorType.LIMITED_FOR_HELP_MOJO ) 468 { 469 PluginUtils.sortMojoParameters( parameters ); 470 } 471 472 for ( Parameter parameter : parameters ) 473 { 474 String expression = getExpression( parameter ); 475 476 if ( StringUtils.isNotEmpty( expression ) && expression.startsWith( "${component." ) ) 477 { 478 // treat it as a component...a requirement, in other words. 479 480 // remove "component." plus expression delimiters 481 String role = expression.substring( "${component.".length(), expression.length() - 1 ); 482 483 String roleHint = null; 484 485 int posRoleHintSeparator = role.indexOf( '#' ); 486 if ( posRoleHintSeparator > 0 ) 487 { 488 roleHint = role.substring( posRoleHintSeparator + 1 ); 489 490 role = role.substring( 0, posRoleHintSeparator ); 491 } 492 493 // TODO: remove deprecated expression 494 requirements.put( parameter.getName(), new Requirement( role, roleHint ) ); 495 } 496 else if ( parameter.getRequirement() != null ) 497 { 498 requirements.put( parameter.getName(), parameter.getRequirement() ); 499 } 500 // don't show readonly parameters in help 501 else if ( type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable() ) 502 { 503 // treat it as a normal parameter. 504 505 w.startElement( "parameter" ); 506 507 GeneratorUtils.element( w, "name", parameter.getName() ); 508 509 if ( parameter.getAlias() != null ) 510 { 511 GeneratorUtils.element( w, "alias", parameter.getAlias() ); 512 } 513 514 writeParameterType( w, type, javadocLinkGenerator, parameter, mojoDescriptor.getGoal() ); 515 516 if ( parameter.getSince() != null ) 517 { 518 w.startElement( "since" ); 519 520 if ( StringUtils.isEmpty( parameter.getSince() ) ) 521 { 522 w.writeText( "No version given" ); 523 } 524 else 525 { 526 w.writeText( parameter.getSince() ); 527 } 528 529 w.endElement(); 530 } 531 532 if ( parameter.getDeprecated() != null ) 533 { 534 if ( StringUtils.isEmpty( parameter.getDeprecated() ) ) 535 { 536 GeneratorUtils.element( w, "deprecated", "No reason given" ); 537 } 538 else 539 { 540 GeneratorUtils.element( w, "deprecated", 541 getTextValue( type, containsXhtmlTextValues, 542 parameter.getDeprecated() ) ); 543 } 544 } 545 546 if ( parameter.getImplementation() != null ) 547 { 548 GeneratorUtils.element( w, "implementation", parameter.getImplementation() ); 549 } 550 551 GeneratorUtils.element( w, "required", Boolean.toString( parameter.isRequired() ) ); 552 553 GeneratorUtils.element( w, "editable", Boolean.toString( parameter.isEditable() ) ); 554 555 GeneratorUtils.element( w, "description", getTextValue( type, containsXhtmlTextValues, 556 parameter.getDescription() ) ); 557 558 if ( StringUtils.isNotEmpty( parameter.getDefaultValue() ) || StringUtils.isNotEmpty( 559 parameter.getExpression() ) ) 560 { 561 configuration.add( parameter ); 562 } 563 564 w.endElement(); 565 } 566 567 } 568 } 569 570 w.endElement(); 571 572 // ---------------------------------------------------------------------- 573 // Configuration 574 // ---------------------------------------------------------------------- 575 576 if ( !configuration.isEmpty() ) 577 { 578 w.startElement( "configuration" ); 579 580 for ( Parameter parameter : configuration ) 581 { 582 if ( type == DescriptorType.LIMITED_FOR_HELP_MOJO && !parameter.isEditable() ) 583 { 584 // don't show readonly parameters in help 585 continue; 586 } 587 588 w.startElement( parameter.getName() ); 589 590 // strip type by parameter type (generics) information 591 String parameterType = StringUtils.chomp( parameter.getType(), "<" ); 592 if ( StringUtils.isNotEmpty( parameterType ) ) 593 { 594 w.addAttribute( "implementation", parameterType ); 595 } 596 597 if ( parameter.getDefaultValue() != null ) 598 { 599 w.addAttribute( "default-value", parameter.getDefaultValue() ); 600 } 601 602 if ( StringUtils.isNotEmpty( parameter.getExpression() ) ) 603 { 604 w.writeText( parameter.getExpression() ); 605 } 606 607 w.endElement(); 608 } 609 610 w.endElement(); 611 } 612 613 // ---------------------------------------------------------------------- 614 // Requirements 615 // ---------------------------------------------------------------------- 616 617 if ( !requirements.isEmpty() && type != DescriptorType.LIMITED_FOR_HELP_MOJO ) 618 { 619 w.startElement( "requirements" ); 620 621 for ( Map.Entry<String, Requirement> entry : requirements.entrySet() ) 622 { 623 String key = entry.getKey(); 624 Requirement requirement = entry.getValue(); 625 626 w.startElement( "requirement" ); 627 628 GeneratorUtils.element( w, "role", requirement.getRole() ); 629 630 if ( StringUtils.isNotEmpty( requirement.getRoleHint() ) ) 631 { 632 GeneratorUtils.element( w, "role-hint", requirement.getRoleHint() ); 633 } 634 635 GeneratorUtils.element( w, "field-name", key ); 636 637 w.endElement(); 638 } 639 640 w.endElement(); 641 } 642 643 w.endElement(); 644 } 645 646 /** 647 * Writes parameter type information and potentially also the related javadoc URL. 648 * @param w 649 * @param type 650 * @param javadocLinkGenerator 651 * @param parameter 652 * @param goal 653 */ 654 protected void writeParameterType( XMLWriter w, DescriptorType type, JavadocLinkGenerator javadocLinkGenerator, 655 Parameter parameter, String goal ) 656 { 657 String parameterType = parameter.getType(); 658 659 if ( type == DescriptorType.STANDARD ) 660 { 661 // strip type by parameter type (generics) information for standard plugin descriptor 662 parameterType = StringUtils.chomp( parameterType, "<" ); 663 } 664 GeneratorUtils.element( w, "type", parameterType ); 665 666 if ( type == DescriptorType.XHTML && javadocLinkGenerator != null ) 667 { 668 // skip primitives which never has javadoc 669 if ( parameter.getType().indexOf( '.' ) == -1 ) 670 { 671 LOG.debug( "Javadoc URLs are not available for primitive types like {}", 672 parameter.getType() ); 673 } 674 else 675 { 676 try 677 { 678 URI javadocUrl = getJavadocUrlForType( javadocLinkGenerator, parameterType ); 679 GeneratorUtils.element( w, "typeJavadocUrl", javadocUrl.toString() ); 680 } 681 catch ( IllegalArgumentException e ) 682 { 683 LOG.warn( "Could not get javadoc URL for type {} of parameter {} from goal {}: {}", 684 parameter.getType(), parameter.getName(), goal, 685 e.getMessage() ); 686 } 687 } 688 } 689 } 690 691 static URI getJavadocUrlForType( JavadocLinkGenerator javadocLinkGenerator, String type ) 692 { 693 final String binaryName; 694 int startOfParameterType = type.indexOf( "<" ); 695 if ( startOfParameterType != -1 ) 696 { 697 // parse parameter type 698 String mainType = type.substring( 0, startOfParameterType ); 699 700 // some heuristics here 701 String[] parameterTypes = type.substring( startOfParameterType + 1, type.lastIndexOf( ">" ) ) 702 .split( ",\\s*" ); 703 switch ( parameterTypes.length ) 704 { 705 case 1: // if only one parameter type, assume collection, first parameter type is most interesting 706 binaryName = parameterTypes[0]; 707 break; 708 case 2: // if two parameter types assume map, second parameter type is most interesting 709 binaryName = parameterTypes[1]; 710 break; 711 default: 712 // all other cases link to main type 713 binaryName = mainType; 714 } 715 } 716 else 717 { 718 binaryName = type; 719 } 720 return javadocLinkGenerator.createLink( binaryName ); 721 } 722 723 /** 724 * Get the expression value, eventually surrounding it with <code>${ }</code>. 725 * 726 * @param parameter the parameter 727 * @return the expression value 728 */ 729 private String getExpression( Parameter parameter ) 730 { 731 String expression = parameter.getExpression(); 732 if ( StringUtils.isNotBlank( expression ) && !expression.contains( "${" ) ) 733 { 734 expression = "${" + expression.trim() + "}"; 735 parameter.setExpression( expression ); 736 } 737 return expression; 738 } 739}