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.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import javax.xml.bind.annotation.XmlAccessType; 024import javax.xml.bind.annotation.XmlAccessorType; 025import javax.xml.bind.annotation.XmlAttribute; 026import javax.xml.bind.annotation.XmlElement; 027import javax.xml.bind.annotation.XmlRootElement; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.spi.Metadata; 031import org.apache.camel.spi.RestConfiguration; 032import org.apache.camel.util.CamelContextHelper; 033 034/** 035 * To configure rest 036 */ 037@Metadata(label = "rest") 038@XmlRootElement(name = "restConfiguration") 039@XmlAccessorType(XmlAccessType.FIELD) 040public class RestConfigurationDefinition { 041 042 @XmlAttribute 043 private String component; 044 045 @XmlAttribute 046 private String scheme; 047 048 @XmlAttribute 049 private String host; 050 051 @XmlAttribute 052 private String port; 053 054 @XmlAttribute 055 private String contextPath; 056 057 @XmlAttribute 058 private RestHostNameResolver hostNameResolver; 059 060 @XmlAttribute @Metadata(defaultValue = "auto") 061 private RestBindingMode bindingMode; 062 063 @XmlAttribute 064 private Boolean skipBindingOnErrorCode; 065 066 @XmlAttribute 067 private Boolean enableCORS; 068 069 @XmlAttribute 070 private String jsonDataFormat; 071 072 @XmlAttribute 073 private String xmlDataFormat; 074 075 @XmlElement(name = "componentProperty") 076 private List<RestPropertyDefinition> componentProperties = new ArrayList<RestPropertyDefinition>(); 077 078 @XmlElement(name = "endpointProperty") 079 private List<RestPropertyDefinition> endpointProperties = new ArrayList<RestPropertyDefinition>(); 080 081 @XmlElement(name = "consumerProperty") 082 private List<RestPropertyDefinition> consumerProperties = new ArrayList<RestPropertyDefinition>(); 083 084 @XmlElement(name = "dataFormatProperty") 085 private List<RestPropertyDefinition> dataFormatProperties = new ArrayList<RestPropertyDefinition>(); 086 087 @XmlElement(name = "corsHeaders") 088 private List<RestPropertyDefinition> corsHeaders = new ArrayList<RestPropertyDefinition>(); 089 090 public String getComponent() { 091 return component; 092 } 093 094 /** 095 * The Camel Rest component to use for the REST transport, such as restlet, spark-rest. 096 * If no component has been explicit configured, then Camel will lookup if there is a Camel component 097 * that integrates with the Rest DSL, or if a org.apache.camel.spi.RestConsumerFactory is registered in the registry. 098 * If either one is found, then that is being used. 099 */ 100 public void setComponent(String component) { 101 this.component = component; 102 } 103 104 public String getScheme() { 105 return scheme; 106 } 107 108 /** 109 * The scheme to use for exposing the REST service. Usually http or https is supported. 110 * <p/> 111 * The default value is http 112 */ 113 public void setScheme(String scheme) { 114 this.scheme = scheme; 115 } 116 117 public String getHost() { 118 return host; 119 } 120 121 /** 122 * The hostname to use for exposing the REST service. 123 */ 124 public void setHost(String host) { 125 this.host = host; 126 } 127 128 public String getPort() { 129 return port; 130 } 131 132 /** 133 * The port number to use for exposing the REST service. 134 * Notice if you use servlet component then the port number configured here does not apply, 135 * as the port number in use is the actual port number the servlet component is using. 136 * eg if using Apache Tomcat its the tomcat http port, if using Apache Karaf its the HTTP service in Karaf 137 * that uses port 8181 by default etc. Though in those situations setting the port number here, 138 * allows tooling and JMX to know the port number, so its recommended to set the port number 139 * to the number that the servlet engine uses. 140 */ 141 public void setPort(String port) { 142 this.port = port; 143 } 144 145 public String getContextPath() { 146 return contextPath; 147 } 148 149 /** 150 * Sets a leading context-path the REST services will be using. 151 * This can be used when using components such as SERVLET where the deployed web application is deployed using a context-path. 152 */ 153 public void setContextPath(String contextPath) { 154 this.contextPath = contextPath; 155 } 156 157 public RestHostNameResolver getHostNameResolver() { 158 return hostNameResolver; 159 } 160 161 /** 162 * If no hostname has been explicit configured, then this resolver is used to compute the hostname the REST service will be using. 163 */ 164 public void setHostNameResolver(RestHostNameResolver hostNameResolver) { 165 this.hostNameResolver = hostNameResolver; 166 } 167 168 public RestBindingMode getBindingMode() { 169 return bindingMode; 170 } 171 172 /** 173 * Sets the binding mode to use. 174 * <p/> 175 * The default value is auto 176 */ 177 public void setBindingMode(RestBindingMode bindingMode) { 178 this.bindingMode = bindingMode; 179 } 180 181 public Boolean getSkipBindingOnErrorCode() { 182 return skipBindingOnErrorCode; 183 } 184 185 /** 186 * Whether to skip binding on output if there is a custom HTTP error code header. 187 * This allows to build custom error messages that do not bind to json / xml etc, as success messages otherwise will do. 188 */ 189 public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) { 190 this.skipBindingOnErrorCode = skipBindingOnErrorCode; 191 } 192 193 public Boolean getEnableCORS() { 194 return enableCORS; 195 } 196 197 /** 198 * Whether to enable CORS headers in the HTTP response. 199 * <p/> 200 * The default value is false. 201 */ 202 public void setEnableCORS(Boolean enableCORS) { 203 this.enableCORS = enableCORS; 204 } 205 206 public String getJsonDataFormat() { 207 return jsonDataFormat; 208 } 209 210 /** 211 * Name of specific json data format to use. 212 * By default json-jackson will be used. 213 * Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance. 214 */ 215 public void setJsonDataFormat(String jsonDataFormat) { 216 this.jsonDataFormat = jsonDataFormat; 217 } 218 219 public String getXmlDataFormat() { 220 return xmlDataFormat; 221 } 222 223 /** 224 * Name of specific XML data format to use. 225 * By default jaxb will be used. 226 * Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance. 227 */ 228 public void setXmlDataFormat(String xmlDataFormat) { 229 this.xmlDataFormat = xmlDataFormat; 230 } 231 232 public List<RestPropertyDefinition> getComponentProperties() { 233 return componentProperties; 234 } 235 236 /** 237 * Allows to configure as many additional properties for the rest component in use. 238 */ 239 public void setComponentProperties(List<RestPropertyDefinition> componentProperties) { 240 this.componentProperties = componentProperties; 241 } 242 243 public List<RestPropertyDefinition> getEndpointProperties() { 244 return endpointProperties; 245 } 246 247 /** 248 * Allows to configure as many additional properties for the rest endpoint in use. 249 */ 250 public void setEndpointProperties(List<RestPropertyDefinition> endpointProperties) { 251 this.endpointProperties = endpointProperties; 252 } 253 254 public List<RestPropertyDefinition> getConsumerProperties() { 255 return consumerProperties; 256 } 257 258 /** 259 * Allows to configure as many additional properties for the rest consumer in use. 260 */ 261 public void setConsumerProperties(List<RestPropertyDefinition> consumerProperties) { 262 this.consumerProperties = consumerProperties; 263 } 264 265 public List<RestPropertyDefinition> getDataFormatProperties() { 266 return dataFormatProperties; 267 } 268 269 /** 270 * Allows to configure as many additional properties for the data formats in use. 271 * For example set property prettyPrint to true to have json outputted in pretty mode. 272 * The properties can be prefixed to denote the option is only for either JSON or XML and for either the IN or the OUT. 273 * The prefixes are: 274 * <ul> 275 * <li>json.in.</li> 276 * <li>json.out.</li> 277 * <li>xml.in.</li> 278 * <li>xml.out.</li> 279 * </ul> 280 * For example a key with value "xml.out.mustBeJAXBElement" is only for the XML data format for the outgoing. 281 * A key without a prefix is a common key for all situations. 282 */ 283 public void setDataFormatProperties(List<RestPropertyDefinition> dataFormatProperties) { 284 this.dataFormatProperties = dataFormatProperties; 285 } 286 287 public List<RestPropertyDefinition> getCorsHeaders() { 288 return corsHeaders; 289 } 290 291 /** 292 * Allows to configure custom CORS headers. 293 */ 294 public void setCorsHeaders(List<RestPropertyDefinition> corsHeaders) { 295 this.corsHeaders = corsHeaders; 296 } 297 298 // Fluent API 299 //------------------------------------------------------------------------- 300 301 /** 302 * To use a specific Camel rest component 303 */ 304 public RestConfigurationDefinition component(String componentId) { 305 setComponent(componentId); 306 return this; 307 } 308 309 /** 310 * To use a specific scheme such as http/https 311 */ 312 public RestConfigurationDefinition scheme(String scheme) { 313 setScheme(scheme); 314 return this; 315 } 316 317 /** 318 * To define the host to use, such as 0.0.0.0 or localhost 319 */ 320 public RestConfigurationDefinition host(String host) { 321 setHost(host); 322 return this; 323 } 324 325 /** 326 * To specify the port number to use for the REST service 327 */ 328 public RestConfigurationDefinition port(int port) { 329 setPort("" + port); 330 return this; 331 } 332 333 /** 334 * To specify the port number to use for the REST service 335 */ 336 public RestConfigurationDefinition port(String port) { 337 setPort(port); 338 return this; 339 } 340 341 /** 342 * Sets a leading context-path the REST services will be using. 343 * <p/> 344 * This can be used when using components such as <tt>camel-servlet</tt> where the deployed web application 345 * is deployed using a context-path. 346 */ 347 public RestConfigurationDefinition contextPath(String contextPath) { 348 setContextPath(contextPath); 349 return this; 350 } 351 352 /** 353 * To specify the hostname resolver 354 */ 355 public RestConfigurationDefinition hostNameResolver(RestHostNameResolver hostNameResolver) { 356 setHostNameResolver(hostNameResolver); 357 return this; 358 } 359 360 /** 361 * To specify the binding mode 362 */ 363 public RestConfigurationDefinition bindingMode(RestBindingMode bindingMode) { 364 setBindingMode(bindingMode); 365 return this; 366 } 367 368 /** 369 * To specify whether to skip binding output if there is a custom HTTP error code 370 */ 371 public RestConfigurationDefinition skipBindingOnErrorCode(boolean skipBindingOnErrorCode) { 372 setSkipBindingOnErrorCode(skipBindingOnErrorCode); 373 return this; 374 } 375 376 /** 377 * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response. 378 */ 379 public RestConfigurationDefinition enableCORS(boolean enableCORS) { 380 setEnableCORS(enableCORS); 381 return this; 382 } 383 384 /** 385 * To use a specific json data format 386 * <p/> 387 * <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance. 388 * 389 * @param name name of the data format to {@link org.apache.camel.CamelContext#resolveDataFormat(java.lang.String) resolve} 390 */ 391 public RestConfigurationDefinition jsonDataFormat(String name) { 392 setJsonDataFormat(name); 393 return this; 394 } 395 396 /** 397 * To use a specific XML data format 398 * <p/> 399 * <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance. 400 * 401 * @param name name of the data format to {@link org.apache.camel.CamelContext#resolveDataFormat(java.lang.String) resolve} 402 */ 403 public RestConfigurationDefinition xmlDataFormat(String name) { 404 setXmlDataFormat(name); 405 return this; 406 } 407 408 /** 409 * For additional configuration options on component level 410 */ 411 public RestConfigurationDefinition componentProperty(String key, String value) { 412 RestPropertyDefinition prop = new RestPropertyDefinition(); 413 prop.setKey(key); 414 prop.setValue(value); 415 getComponentProperties().add(prop); 416 return this; 417 } 418 419 /** 420 * For additional configuration options on endpoint level 421 */ 422 public RestConfigurationDefinition endpointProperty(String key, String value) { 423 RestPropertyDefinition prop = new RestPropertyDefinition(); 424 prop.setKey(key); 425 prop.setValue(value); 426 getEndpointProperties().add(prop); 427 return this; 428 } 429 430 /** 431 * For additional configuration options on consumer level 432 */ 433 public RestConfigurationDefinition consumerProperty(String key, String value) { 434 RestPropertyDefinition prop = new RestPropertyDefinition(); 435 prop.setKey(key); 436 prop.setValue(value); 437 getConsumerProperties().add(prop); 438 return this; 439 } 440 441 /** 442 * For additional configuration options on data format level 443 */ 444 public RestConfigurationDefinition dataFormatProperty(String key, String value) { 445 RestPropertyDefinition prop = new RestPropertyDefinition(); 446 prop.setKey(key); 447 prop.setValue(value); 448 getDataFormatProperties().add(prop); 449 return this; 450 } 451 452 /** 453 * For configuring CORS headers 454 */ 455 public RestConfigurationDefinition corsHeaderProperty(String key, String value) { 456 RestPropertyDefinition prop = new RestPropertyDefinition(); 457 prop.setKey(key); 458 prop.setValue(value); 459 getCorsHeaders().add(prop); 460 return this; 461 } 462 463 // Implementation 464 //------------------------------------------------------------------------- 465 466 /** 467 * Creates a {@link org.apache.camel.spi.RestConfiguration} instance based on the definition 468 * 469 * @param context the camel context 470 * @return the configuration 471 * @throws Exception is thrown if error creating the configuration 472 */ 473 public RestConfiguration asRestConfiguration(CamelContext context) throws Exception { 474 RestConfiguration answer = new RestConfiguration(); 475 if (component != null) { 476 answer.setComponent(CamelContextHelper.parseText(context, component)); 477 } 478 if (scheme != null) { 479 answer.setScheme(CamelContextHelper.parseText(context, scheme)); 480 } 481 if (host != null) { 482 answer.setHost(CamelContextHelper.parseText(context, host)); 483 } 484 if (port != null) { 485 answer.setPort(CamelContextHelper.parseInteger(context, port)); 486 } 487 if (contextPath != null) { 488 answer.setContextPath(CamelContextHelper.parseText(context, contextPath)); 489 } 490 if (hostNameResolver != null) { 491 answer.setRestHostNameResolver(hostNameResolver.name()); 492 } 493 if (bindingMode != null) { 494 answer.setBindingMode(bindingMode.name()); 495 } 496 if (skipBindingOnErrorCode != null) { 497 answer.setSkipBindingOnErrorCode(skipBindingOnErrorCode); 498 } 499 if (enableCORS != null) { 500 answer.setEnableCORS(enableCORS); 501 } 502 if (jsonDataFormat != null) { 503 answer.setJsonDataFormat(jsonDataFormat); 504 } 505 if (xmlDataFormat != null) { 506 answer.setXmlDataFormat(xmlDataFormat); 507 } 508 if (!componentProperties.isEmpty()) { 509 Map<String, Object> props = new HashMap<String, Object>(); 510 for (RestPropertyDefinition prop : componentProperties) { 511 String key = prop.getKey(); 512 String value = CamelContextHelper.parseText(context, prop.getValue()); 513 props.put(key, value); 514 } 515 answer.setComponentProperties(props); 516 } 517 if (!endpointProperties.isEmpty()) { 518 Map<String, Object> props = new HashMap<String, Object>(); 519 for (RestPropertyDefinition prop : endpointProperties) { 520 String key = prop.getKey(); 521 String value = CamelContextHelper.parseText(context, prop.getValue()); 522 props.put(key, value); 523 } 524 answer.setEndpointProperties(props); 525 } 526 if (!consumerProperties.isEmpty()) { 527 Map<String, Object> props = new HashMap<String, Object>(); 528 for (RestPropertyDefinition prop : consumerProperties) { 529 String key = prop.getKey(); 530 String value = CamelContextHelper.parseText(context, prop.getValue()); 531 props.put(key, value); 532 } 533 answer.setConsumerProperties(props); 534 } 535 if (!dataFormatProperties.isEmpty()) { 536 Map<String, Object> props = new HashMap<String, Object>(); 537 for (RestPropertyDefinition prop : dataFormatProperties) { 538 String key = prop.getKey(); 539 String value = CamelContextHelper.parseText(context, prop.getValue()); 540 props.put(key, value); 541 } 542 answer.setDataFormatProperties(props); 543 } 544 if (!corsHeaders.isEmpty()) { 545 Map<String, String> props = new HashMap<String, String>(); 546 for (RestPropertyDefinition prop : corsHeaders) { 547 String key = prop.getKey(); 548 String value = CamelContextHelper.parseText(context, prop.getValue()); 549 props.put(key, value); 550 } 551 answer.setCorsHeaders(props); 552 } 553 return answer; 554 } 555 556}