001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.model.rest; 018 019import java.net.URISyntaxException; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlAttribute; 029import javax.xml.bind.annotation.XmlElementRef; 030import javax.xml.bind.annotation.XmlRootElement; 031 032import org.apache.camel.CamelContext; 033import org.apache.camel.model.OptionalIdentifiedDefinition; 034import org.apache.camel.model.ProcessorDefinition; 035import org.apache.camel.model.RouteDefinition; 036import org.apache.camel.model.ToDefinition; 037import org.apache.camel.model.ToDynamicDefinition; 038import org.apache.camel.spi.Metadata; 039import org.apache.camel.spi.RestConfiguration; 040import org.apache.camel.util.FileUtil; 041import org.apache.camel.util.ObjectHelper; 042import org.apache.camel.util.URISupport; 043 044/** 045 * Defines a rest service using the rest-dsl 046 */ 047@Metadata(label = "rest") 048@XmlRootElement(name = "rest") 049@XmlAccessorType(XmlAccessType.FIELD) 050public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> { 051 052 @XmlAttribute 053 private String path; 054 055 @XmlAttribute 056 private String tag; 057 058 @XmlAttribute 059 private String consumes; 060 061 @XmlAttribute 062 private String produces; 063 064 @XmlAttribute @Metadata(defaultValue = "auto") 065 private RestBindingMode bindingMode; 066 067 @XmlAttribute 068 private Boolean skipBindingOnErrorCode; 069 070 @XmlAttribute 071 private Boolean enableCORS; 072 073 @XmlAttribute 074 private Boolean apiDocs; 075 076 @XmlElementRef 077 private List<VerbDefinition> verbs = new ArrayList<VerbDefinition>(); 078 079 @Override 080 public String getLabel() { 081 return "rest"; 082 } 083 084 public String getPath() { 085 return path; 086 } 087 088 /** 089 * Path of the rest service, such as "/foo" 090 */ 091 public void setPath(String path) { 092 this.path = path; 093 } 094 095 public String getTag() { 096 return tag; 097 } 098 099 /** 100 * To configure a special tag for the operations within this rest definition. 101 */ 102 public void setTag(String tag) { 103 this.tag = tag; 104 } 105 106 public String getConsumes() { 107 return consumes; 108 } 109 110 /** 111 * To define the content type what the REST service consumes (accept as input), such as application/xml or application/json. 112 * This option will override what may be configured on a parent level 113 */ 114 public void setConsumes(String consumes) { 115 this.consumes = consumes; 116 } 117 118 public String getProduces() { 119 return produces; 120 } 121 122 /** 123 * To define the content type what the REST service produces (uses for output), such as application/xml or application/json 124 * This option will override what may be configured on a parent level 125 */ 126 public void setProduces(String produces) { 127 this.produces = produces; 128 } 129 130 public RestBindingMode getBindingMode() { 131 return bindingMode; 132 } 133 134 /** 135 * Sets the binding mode to use. 136 * This option will override what may be configured on a parent level 137 * <p/> 138 * The default value is auto 139 */ 140 public void setBindingMode(RestBindingMode bindingMode) { 141 this.bindingMode = bindingMode; 142 } 143 144 public List<VerbDefinition> getVerbs() { 145 return verbs; 146 } 147 148 /** 149 * The HTTP verbs this REST service accepts and uses 150 */ 151 public void setVerbs(List<VerbDefinition> verbs) { 152 this.verbs = verbs; 153 } 154 155 public Boolean getSkipBindingOnErrorCode() { 156 return skipBindingOnErrorCode; 157 } 158 159 /** 160 * Whether to skip binding on output if there is a custom HTTP error code header. 161 * This allows to build custom error messages that do not bind to json / xml etc, as success messages otherwise will do. 162 * This option will override what may be configured on a parent level 163 */ 164 public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) { 165 this.skipBindingOnErrorCode = skipBindingOnErrorCode; 166 } 167 168 public Boolean getEnableCORS() { 169 return enableCORS; 170 } 171 172 /** 173 * Whether to enable CORS headers in the HTTP response. 174 * This option will override what may be configured on a parent level 175 * <p/> 176 * The default value is false. 177 */ 178 public void setEnableCORS(Boolean enableCORS) { 179 this.enableCORS = enableCORS; 180 } 181 182 public Boolean getApiDocs() { 183 return apiDocs; 184 } 185 186 /** 187 * Whether to include or exclude the VerbDefinition in API documentation. 188 * This option will override what may be configured on a parent level 189 * <p/> 190 * The default value is true. 191 */ 192 public void setApiDocs(Boolean apiDocs) { 193 this.apiDocs = apiDocs; 194 } 195 196 // Fluent API 197 //------------------------------------------------------------------------- 198 199 /** 200 * To set the base path of this REST service 201 */ 202 public RestDefinition path(String path) { 203 setPath(path); 204 return this; 205 } 206 207 /** 208 * To set the tag to use of this REST service 209 */ 210 public RestDefinition tag(String tag) { 211 setTag(tag); 212 return this; 213 } 214 215 public RestDefinition get() { 216 return addVerb("get", null); 217 } 218 219 public RestDefinition get(String uri) { 220 return addVerb("get", uri); 221 } 222 223 public RestDefinition post() { 224 return addVerb("post", null); 225 } 226 227 public RestDefinition post(String uri) { 228 return addVerb("post", uri); 229 } 230 231 public RestDefinition put() { 232 return addVerb("put", null); 233 } 234 235 public RestDefinition put(String uri) { 236 return addVerb("put", uri); 237 } 238 239 public RestDefinition delete() { 240 return addVerb("delete", null); 241 } 242 243 public RestDefinition delete(String uri) { 244 return addVerb("delete", uri); 245 } 246 247 public RestDefinition head() { 248 return addVerb("head", null); 249 } 250 251 public RestDefinition head(String uri) { 252 return addVerb("head", uri); 253 } 254 255 @Deprecated 256 public RestDefinition options() { 257 return addVerb("options", null); 258 } 259 260 @Deprecated 261 public RestDefinition options(String uri) { 262 return addVerb("options", uri); 263 } 264 265 public RestDefinition verb(String verb) { 266 return addVerb(verb, null); 267 } 268 269 public RestDefinition verb(String verb, String uri) { 270 return addVerb(verb, uri); 271 } 272 273 @Override 274 public RestDefinition id(String id) { 275 if (getVerbs().isEmpty()) { 276 super.id(id); 277 } else { 278 // add on last verb as that is how the Java DSL works 279 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 280 verb.id(id); 281 } 282 283 return this; 284 } 285 286 @Override 287 public RestDefinition description(String text) { 288 if (getVerbs().isEmpty()) { 289 super.description(text); 290 } else { 291 // add on last verb as that is how the Java DSL works 292 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 293 verb.description(text); 294 } 295 296 return this; 297 } 298 299 @Override 300 public RestDefinition description(String id, String text, String lang) { 301 if (getVerbs().isEmpty()) { 302 super.description(id, text, lang); 303 } else { 304 // add on last verb as that is how the Java DSL works 305 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 306 verb.description(id, text, lang); 307 } 308 309 return this; 310 } 311 312 public RestDefinition consumes(String mediaType) { 313 if (getVerbs().isEmpty()) { 314 this.consumes = mediaType; 315 } else { 316 // add on last verb as that is how the Java DSL works 317 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 318 verb.setConsumes(mediaType); 319 } 320 321 return this; 322 } 323 324 public RestOperationParamDefinition param() { 325 if (getVerbs().isEmpty()) { 326 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 327 } 328 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 329 return param(verb); 330 } 331 332 public RestDefinition param(RestOperationParamDefinition param) { 333 if (getVerbs().isEmpty()) { 334 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 335 } 336 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 337 verb.getParams().add(param); 338 return this; 339 } 340 341 public RestDefinition params(List<RestOperationParamDefinition> params) { 342 if (getVerbs().isEmpty()) { 343 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 344 } 345 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 346 verb.getParams().addAll(params); 347 return this; 348 } 349 350 public RestOperationParamDefinition param(VerbDefinition verb) { 351 return new RestOperationParamDefinition(verb); 352 } 353 354 public RestDefinition responseMessage(RestOperationResponseMsgDefinition msg) { 355 if (getVerbs().isEmpty()) { 356 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 357 } 358 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 359 verb.getResponseMsgs().add(msg); 360 return this; 361 } 362 363 public RestOperationResponseMsgDefinition responseMessage() { 364 if (getVerbs().isEmpty()) { 365 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 366 } 367 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 368 return responseMessage(verb); 369 } 370 371 public RestOperationResponseMsgDefinition responseMessage(VerbDefinition verb) { 372 return new RestOperationResponseMsgDefinition(verb); 373 } 374 375 public RestDefinition responseMessages(List<RestOperationResponseMsgDefinition> msgs) { 376 if (getVerbs().isEmpty()) { 377 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 378 } 379 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 380 verb.getResponseMsgs().addAll(msgs); 381 return this; 382 } 383 384 public RestDefinition produces(String mediaType) { 385 if (getVerbs().isEmpty()) { 386 this.produces = mediaType; 387 } else { 388 // add on last verb as that is how the Java DSL works 389 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 390 verb.setProduces(mediaType); 391 } 392 393 return this; 394 } 395 396 public RestDefinition type(Class<?> classType) { 397 // add to last verb 398 if (getVerbs().isEmpty()) { 399 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 400 } 401 402 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 403 verb.setType(classType.getCanonicalName()); 404 return this; 405 } 406 407 public RestDefinition typeList(Class<?> classType) { 408 // add to last verb 409 if (getVerbs().isEmpty()) { 410 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 411 } 412 413 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 414 // list should end with [] to indicate array 415 verb.setType(classType.getCanonicalName() + "[]"); 416 return this; 417 } 418 419 public RestDefinition outType(Class<?> classType) { 420 // add to last verb 421 if (getVerbs().isEmpty()) { 422 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 423 } 424 425 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 426 verb.setOutType(classType.getCanonicalName()); 427 return this; 428 } 429 430 public RestDefinition outTypeList(Class<?> classType) { 431 // add to last verb 432 if (getVerbs().isEmpty()) { 433 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 434 } 435 436 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 437 // list should end with [] to indicate array 438 verb.setOutType(classType.getCanonicalName() + "[]"); 439 return this; 440 } 441 442 public RestDefinition bindingMode(RestBindingMode mode) { 443 if (getVerbs().isEmpty()) { 444 this.bindingMode = mode; 445 } else { 446 // add on last verb as that is how the Java DSL works 447 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 448 verb.setBindingMode(mode); 449 } 450 451 return this; 452 } 453 454 public RestDefinition skipBindingOnErrorCode(boolean skipBindingOnErrorCode) { 455 if (getVerbs().isEmpty()) { 456 this.skipBindingOnErrorCode = skipBindingOnErrorCode; 457 } else { 458 // add on last verb as that is how the Java DSL works 459 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 460 verb.setSkipBindingOnErrorCode(skipBindingOnErrorCode); 461 } 462 463 return this; 464 } 465 466 public RestDefinition enableCORS(boolean enableCORS) { 467 if (getVerbs().isEmpty()) { 468 this.enableCORS = enableCORS; 469 } else { 470 // add on last verb as that is how the Java DSL works 471 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 472 verb.setEnableCORS(enableCORS); 473 } 474 475 return this; 476 } 477 478 /** 479 * Include or exclude the current Rest Definition in API documentation. 480 * <p/> 481 * The default value is true. 482 */ 483 public RestDefinition apiDocs(Boolean apiDocs) { 484 if (getVerbs().isEmpty()) { 485 this.apiDocs = apiDocs; 486 } else { 487 // add on last verb as that is how the Java DSL works 488 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 489 verb.setApiDocs(apiDocs); 490 } 491 492 return this; 493 } 494 495 /** 496 * Routes directly to the given static endpoint. 497 * <p/> 498 * If you need additional routing capabilities, then use {@link #route()} instead. 499 * 500 * @param uri the uri of the endpoint 501 * @return this builder 502 */ 503 public RestDefinition to(String uri) { 504 // add to last verb 505 if (getVerbs().isEmpty()) { 506 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 507 } 508 509 ToDefinition to = new ToDefinition(uri); 510 511 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 512 verb.setTo(to); 513 return this; 514 } 515 516 /** 517 * Routes directly to the given dynamic endpoint. 518 * <p/> 519 * If you need additional routing capabilities, then use {@link #route()} instead. 520 * 521 * @param uri the uri of the endpoint 522 * @return this builder 523 */ 524 public RestDefinition toD(String uri) { 525 // add to last verb 526 if (getVerbs().isEmpty()) { 527 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 528 } 529 530 ToDynamicDefinition to = new ToDynamicDefinition(uri); 531 532 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 533 verb.setToD(to); 534 return this; 535 } 536 537 public RouteDefinition route() { 538 // add to last verb 539 if (getVerbs().isEmpty()) { 540 throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); 541 } 542 543 // link them together so we can navigate using Java DSL 544 RouteDefinition route = new RouteDefinition(); 545 route.setRestDefinition(this); 546 VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); 547 verb.setRoute(route); 548 return route; 549 } 550 551 // Implementation 552 //------------------------------------------------------------------------- 553 554 private RestDefinition addVerb(String verb, String uri) { 555 VerbDefinition answer; 556 557 if ("get".equals(verb)) { 558 answer = new GetVerbDefinition(); 559 } else if ("post".equals(verb)) { 560 answer = new PostVerbDefinition(); 561 } else if ("delete".equals(verb)) { 562 answer = new DeleteVerbDefinition(); 563 } else if ("head".equals(verb)) { 564 answer = new HeadVerbDefinition(); 565 } else if ("put".equals(verb)) { 566 answer = new PutVerbDefinition(); 567 } else if ("options".equals(verb)) { 568 answer = new OptionsVerbDefinition(); 569 } else { 570 answer = new VerbDefinition(); 571 answer.setMethod(verb); 572 } 573 getVerbs().add(answer); 574 answer.setRest(this); 575 answer.setUri(uri); 576 return this; 577 } 578 579 /** 580 * Transforms this REST definition into a list of {@link org.apache.camel.model.RouteDefinition} which 581 * Camel routing engine can add and run. This allows us to define REST services using this 582 * REST DSL and turn those into regular Camel routes. 583 */ 584 public List<RouteDefinition> asRouteDefinition(CamelContext camelContext) { 585 // sanity check this rest definition do not have duplicates 586 validateUniquePaths(); 587 588 List<RouteDefinition> answer = new ArrayList<RouteDefinition>(); 589 if (camelContext.getRestConfigurations().isEmpty()) { 590 camelContext.getRestConfiguration(); 591 } 592 for (RestConfiguration config : camelContext.getRestConfigurations()) { 593 addRouteDefinition(camelContext, answer, config.getComponent()); 594 } 595 return answer; 596 } 597 598 protected void validateUniquePaths() { 599 Set<String> paths = new HashSet<String>(); 600 for (VerbDefinition verb : verbs) { 601 String path = verb.asVerb(); 602 if (verb.getUri() != null) { 603 path += ":" + verb.getUri(); 604 } 605 if (!paths.add(path)) { 606 throw new IllegalArgumentException("Duplicate verb detected in rest-dsl: " + path); 607 } 608 } 609 } 610 611 /** 612 * Transforms the rest api configuration into a {@link org.apache.camel.model.RouteDefinition} which 613 * Camel routing engine uses to service the rest api docs. 614 */ 615 public static RouteDefinition asRouteApiDefinition(CamelContext camelContext, RestConfiguration configuration) { 616 RouteDefinition answer = new RouteDefinition(); 617 618 // create the from endpoint uri which is using the rest-api component 619 String from = "rest-api:" + configuration.getApiContextPath(); 620 621 // append options 622 Map<String, Object> options = new HashMap<String, Object>(); 623 624 String routeId = configuration.getApiContextRouteId(); 625 if (routeId == null) { 626 routeId = answer.idOrCreate(camelContext.getNodeIdFactory()); 627 } 628 options.put("routeId", routeId); 629 if (configuration.getComponent() != null && !configuration.getComponent().isEmpty()) { 630 options.put("componentName", configuration.getComponent()); 631 } 632 if (configuration.getApiContextIdPattern() != null) { 633 options.put("contextIdPattern", configuration.getApiContextIdPattern()); 634 } 635 636 if (!options.isEmpty()) { 637 String query; 638 try { 639 query = URISupport.createQueryString(options); 640 } catch (URISyntaxException e) { 641 throw ObjectHelper.wrapRuntimeCamelException(e); 642 } 643 from = from + "?" + query; 644 } 645 646 // we use the same uri as the producer (so we have a little route for the rest api) 647 String to = from; 648 answer.fromRest(from); 649 answer.id(routeId); 650 answer.to(to); 651 652 return answer; 653 } 654 655 private void addRouteDefinition(CamelContext camelContext, List<RouteDefinition> answer, String component) { 656 for (VerbDefinition verb : getVerbs()) { 657 // either the verb has a singular to or a embedded route 658 RouteDefinition route = verb.getRoute(); 659 if (route == null) { 660 // it was a singular to, so add a new route and add the singular 661 // to as output to this route 662 route = new RouteDefinition(); 663 ProcessorDefinition def = verb.getTo() != null ? verb.getTo() : verb.getToD(); 664 route.getOutputs().add(def); 665 } 666 667 // add the binding 668 RestBindingDefinition binding = new RestBindingDefinition(); 669 binding.setComponent(component); 670 binding.setType(verb.getType()); 671 binding.setOutType(verb.getOutType()); 672 // verb takes precedence over configuration on rest 673 if (verb.getConsumes() != null) { 674 binding.setConsumes(verb.getConsumes()); 675 } else { 676 binding.setConsumes(getConsumes()); 677 } 678 if (verb.getProduces() != null) { 679 binding.setProduces(verb.getProduces()); 680 } else { 681 binding.setProduces(getProduces()); 682 } 683 if (verb.getBindingMode() != null) { 684 binding.setBindingMode(verb.getBindingMode()); 685 } else { 686 binding.setBindingMode(getBindingMode()); 687 } 688 if (verb.getSkipBindingOnErrorCode() != null) { 689 binding.setSkipBindingOnErrorCode(verb.getSkipBindingOnErrorCode()); 690 } else { 691 binding.setSkipBindingOnErrorCode(getSkipBindingOnErrorCode()); 692 } 693 if (verb.getEnableCORS() != null) { 694 binding.setEnableCORS(verb.getEnableCORS()); 695 } else { 696 binding.setEnableCORS(getEnableCORS()); 697 } 698 // register all the default values for the query parameters 699 for (RestOperationParamDefinition param : verb.getParams()) { 700 if (RestParamType.query == param.getType() && param.getDefaultValue() != null) { 701 binding.addDefaultValue(param.getName(), param.getDefaultValue()); 702 } 703 } 704 705 route.getOutputs().add(0, binding); 706 707 // create the from endpoint uri which is using the rest component 708 String from = "rest:" + verb.asVerb() + ":" + buildUri(verb); 709 710 // append options 711 Map<String, Object> options = new HashMap<String, Object>(); 712 // verb takes precedence over configuration on rest 713 if (verb.getConsumes() != null) { 714 options.put("consumes", verb.getConsumes()); 715 } else if (getConsumes() != null) { 716 options.put("consumes", getConsumes()); 717 } 718 if (verb.getProduces() != null) { 719 options.put("produces", verb.getProduces()); 720 } else if (getProduces() != null) { 721 options.put("produces", getProduces()); 722 } 723 724 // append optional type binding information 725 String inType = binding.getType(); 726 if (inType != null) { 727 options.put("inType", inType); 728 } 729 String outType = binding.getOutType(); 730 if (outType != null) { 731 options.put("outType", outType); 732 } 733 // if no route id has been set, then use the verb id as route id 734 if (!route.hasCustomIdAssigned()) { 735 // use id of verb as route id 736 String id = verb.getId(); 737 if (id != null) { 738 route.setId(id); 739 } 740 } 741 String routeId = route.idOrCreate(camelContext.getNodeIdFactory()); 742 verb.setRouteId(routeId); 743 options.put("routeId", routeId); 744 if (component != null && !component.isEmpty()) { 745 options.put("componentName", component); 746 } 747 748 // include optional description, which we favor from 1) to/route description 2) verb description 3) rest description 749 // this allows end users to define general descriptions and override then per to/route or verb 750 String description = verb.getTo() != null ? verb.getTo().getDescriptionText() : route.getDescriptionText(); 751 if (description == null) { 752 description = verb.getDescriptionText(); 753 } 754 if (description == null) { 755 description = getDescriptionText(); 756 } 757 if (description != null) { 758 options.put("description", description); 759 } 760 761 if (!options.isEmpty()) { 762 String query; 763 try { 764 query = URISupport.createQueryString(options); 765 } catch (URISyntaxException e) { 766 throw ObjectHelper.wrapRuntimeCamelException(e); 767 } 768 from = from + "?" + query; 769 } 770 771 String path = getPath(); 772 String s1 = FileUtil.stripTrailingSeparator(path); 773 String s2 = FileUtil.stripLeadingSeparator(verb.getUri()); 774 String allPath; 775 if (s1 != null && s2 != null) { 776 allPath = s1 + "/" + s2; 777 } else if (path != null) { 778 allPath = path; 779 } else { 780 allPath = verb.getUri(); 781 } 782 783 // each {} is a parameter (url templating) 784 String[] arr = allPath.split("\\/"); 785 for (String a : arr) { 786 // need to resolve property placeholders first 787 try { 788 a = camelContext.resolvePropertyPlaceholders(a); 789 } catch (Exception e) { 790 throw ObjectHelper.wrapRuntimeCamelException(e); 791 } 792 if (a.startsWith("{") && a.endsWith("}")) { 793 String key = a.substring(1, a.length() - 1); 794 // merge if exists 795 boolean found = false; 796 for (RestOperationParamDefinition param : verb.getParams()) { 797 // name is mandatory 798 String name = param.getName(); 799 ObjectHelper.notEmpty(name, "parameter name"); 800 // need to resolve property placeholders first 801 try { 802 name = camelContext.resolvePropertyPlaceholders(name); 803 } catch (Exception e) { 804 throw ObjectHelper.wrapRuntimeCamelException(e); 805 } 806 if (name.equalsIgnoreCase(key)) { 807 param.type(RestParamType.path); 808 found = true; 809 break; 810 } 811 } 812 if (!found) { 813 param(verb).name(key).type(RestParamType.path).endParam(); 814 } 815 } 816 } 817 818 if (verb.getType() != null) { 819 String bodyType = verb.getType(); 820 if (bodyType.endsWith("[]")) { 821 bodyType = "List[" + bodyType.substring(0, bodyType.length() - 2) + "]"; 822 } 823 RestOperationParamDefinition param = findParam(verb, RestParamType.body.name()); 824 if (param == null) { 825 // must be body type and set the model class as data type 826 param(verb).name(RestParamType.body.name()).type(RestParamType.body).dataType(bodyType).endParam(); 827 } else { 828 // must be body type and set the model class as data type 829 param.type(RestParamType.body).dataType(bodyType); 830 } 831 } 832 833 // the route should be from this rest endpoint 834 route.fromRest(from); 835 route.id(routeId); 836 route.setRestDefinition(this); 837 answer.add(route); 838 } 839 } 840 841 private String buildUri(VerbDefinition verb) { 842 if (path != null && verb.getUri() != null) { 843 return path + ":" + verb.getUri(); 844 } else if (path != null) { 845 return path; 846 } else if (verb.getUri() != null) { 847 return verb.getUri(); 848 } else { 849 return ""; 850 } 851 } 852 853 private RestOperationParamDefinition findParam(VerbDefinition verb, String name) { 854 for (RestOperationParamDefinition param : verb.getParams()) { 855 if (name.equals(param.getName())) { 856 return param; 857 } 858 } 859 return null; 860 } 861 862}