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;
023
024import javax.xml.bind.annotation.XmlAccessType;
025import javax.xml.bind.annotation.XmlAccessorType;
026import javax.xml.bind.annotation.XmlAttribute;
027import javax.xml.bind.annotation.XmlElement;
028import javax.xml.bind.annotation.XmlRootElement;
029
030import org.apache.camel.CamelContext;
031import org.apache.camel.spi.Metadata;
032import org.apache.camel.spi.RestConfiguration;
033import org.apache.camel.support.CamelContextHelper;
034import org.apache.camel.support.PatternHelper;
035
036/**
037 * To configure rest
038 */
039@Metadata(label = "rest")
040@XmlRootElement(name = "restConfiguration")
041@XmlAccessorType(XmlAccessType.FIELD)
042public class RestConfigurationDefinition {
043
044    @XmlAttribute
045    private String component;
046
047    @XmlAttribute
048    @Metadata(label = "consumer", defaultValue = "swagger")
049    private String apiComponent;
050
051    @XmlAttribute
052    @Metadata(label = "producer")
053    private String producerComponent;
054
055    @XmlAttribute
056    private String scheme;
057
058    @XmlAttribute
059    private String host;
060
061    @XmlAttribute
062    private String apiHost;
063
064    @XmlAttribute
065    @Metadata(defaultValue = "true", label = "consumer")
066    private Boolean useXForwardHeaders;
067
068    @XmlAttribute
069    private String port;
070
071    @XmlAttribute
072    @Metadata(label = "producer")
073    private String producerApiDoc;
074
075    @XmlAttribute
076    @Metadata(label = "consumer")
077    private String contextPath;
078
079    @XmlAttribute
080    @Metadata(label = "consumer")
081    private String apiContextPath;
082
083    @XmlAttribute
084    @Metadata(label = "consumer")
085    private String apiContextRouteId;
086
087    @XmlAttribute
088    @Metadata(label = "consumer")
089    private String apiContextIdPattern;
090
091    @XmlAttribute
092    @Metadata(label = "consumer")
093    private Boolean apiContextListing;
094
095    @XmlAttribute
096    @Metadata(label = "consumer")
097    private Boolean apiVendorExtension;
098
099    @XmlAttribute
100    @Metadata(label = "consumer")
101    private RestHostNameResolver hostNameResolver;
102
103    @XmlAttribute
104    @Metadata(defaultValue = "off")
105    private RestBindingMode bindingMode;
106
107    @XmlAttribute
108    private Boolean skipBindingOnErrorCode;
109
110    @XmlAttribute
111    private Boolean clientRequestValidation;
112
113    @XmlAttribute
114    @Metadata(label = "consumer")
115    private Boolean enableCORS;
116
117    @XmlAttribute
118    private String jsonDataFormat;
119
120    @XmlAttribute
121    private String xmlDataFormat;
122
123    @XmlElement(name = "componentProperty")
124    private List<RestPropertyDefinition> componentProperties = new ArrayList<>();
125
126    @XmlElement(name = "endpointProperty")
127    private List<RestPropertyDefinition> endpointProperties = new ArrayList<>();
128
129    @XmlElement(name = "consumerProperty")
130    @Metadata(label = "consumer")
131    private List<RestPropertyDefinition> consumerProperties = new ArrayList<>();
132
133    @XmlElement(name = "dataFormatProperty")
134    private List<RestPropertyDefinition> dataFormatProperties = new ArrayList<>();
135
136    @XmlElement(name = "apiProperty")
137    @Metadata(label = "consumer")
138    private List<RestPropertyDefinition> apiProperties = new ArrayList<>();
139
140    @XmlElement(name = "corsHeaders")
141    @Metadata(label = "consumer")
142    private List<RestPropertyDefinition> corsHeaders = new ArrayList<>();
143
144    public String getComponent() {
145        return component;
146    }
147
148    /**
149     * The Camel Rest component to use for the REST transport (consumer), such
150     * as netty-http, jetty, servlet, undertow. If no component has been explicit configured,
151     * then Camel will lookup if there is a Camel component that integrates with
152     * the Rest DSL, or if a org.apache.camel.spi.RestConsumerFactory is
153     * registered in the registry. If either one is found, then that is being
154     * used.
155     */
156    public void setComponent(String component) {
157        this.component = component;
158    }
159
160    public String getApiComponent() {
161        return apiComponent;
162    }
163
164    /**
165     * The name of the Camel component to use as the REST API (such as swagger)
166     */
167    public void setApiComponent(String apiComponent) {
168        this.apiComponent = apiComponent;
169    }
170
171    public String getProducerComponent() {
172        return producerComponent;
173    }
174
175    /**
176     * Sets the name of the Camel component to use as the REST producer
177     */
178    public void setProducerComponent(String producerComponent) {
179        this.producerComponent = producerComponent;
180    }
181
182    public String getScheme() {
183        return scheme;
184    }
185
186    /**
187     * The scheme to use for exposing the REST service. Usually http or https is
188     * supported.
189     * <p/>
190     * The default value is http
191     */
192    public void setScheme(String scheme) {
193        this.scheme = scheme;
194    }
195
196    public String getHost() {
197        return host;
198    }
199
200    /**
201     * The hostname to use for exposing the REST service.
202     */
203    public void setHost(String host) {
204        this.host = host;
205    }
206
207    public String getApiHost() {
208        return apiHost;
209    }
210
211    /**
212     * To use an specific hostname for the API documentation (eg swagger)
213     * <p/>
214     * This can be used to override the generated host with this configured
215     * hostname
216     */
217    public void setApiHost(String apiHost) {
218        this.apiHost = apiHost;
219    }
220
221    public String getPort() {
222        return port;
223    }
224
225    /**
226     * The port number to use for exposing the REST service. Notice if you use
227     * servlet component then the port number configured here does not apply, as
228     * the port number in use is the actual port number the servlet component is
229     * using. eg if using Apache Tomcat its the tomcat http port, if using
230     * Apache Karaf its the HTTP service in Karaf that uses port 8181 by default
231     * etc. Though in those situations setting the port number here, allows
232     * tooling and JMX to know the port number, so its recommended to set the
233     * port number to the number that the servlet engine uses.
234     */
235    public void setPort(String port) {
236        this.port = port;
237    }
238
239    public String getProducerApiDoc() {
240        return producerApiDoc;
241    }
242
243    /**
244     * Sets the location of the api document (swagger api) the REST producer
245     * will use to validate the REST uri and query parameters are valid
246     * accordingly to the api document. This requires adding camel-swagger-java
247     * to the classpath, and any miss configuration will let Camel fail on
248     * startup and report the error(s).
249     * <p/>
250     * The location of the api document is loaded from classpath by default, but
251     * you can use <tt>file:</tt> or <tt>http:</tt> to refer to resources to
252     * load from file or http url.
253     */
254    public void setProducerApiDoc(String producerApiDoc) {
255        this.producerApiDoc = producerApiDoc;
256    }
257
258    public String getContextPath() {
259        return contextPath;
260    }
261
262    /**
263     * Sets a leading context-path the REST services will be using.
264     * <p/>
265     * This can be used when using components such as <tt>camel-servlet</tt>
266     * where the deployed web application is deployed using a context-path. Or
267     * for components such as <tt>camel-jetty</tt> or <tt>camel-netty-http</tt>
268     * that includes a HTTP server.
269     */
270    public void setContextPath(String contextPath) {
271        this.contextPath = contextPath;
272    }
273
274    public String getApiContextPath() {
275        return apiContextPath;
276    }
277
278    /**
279     * Sets a leading API context-path the REST API services will be using.
280     * <p/>
281     * This can be used when using components such as <tt>camel-servlet</tt>
282     * where the deployed web application is deployed using a context-path.
283     *
284     * @param contextPath the API context path
285     */
286    public void setApiContextPath(String contextPath) {
287        this.apiContextPath = contextPath;
288    }
289
290    public String getApiContextRouteId() {
291        return apiContextRouteId;
292    }
293
294    /**
295     * Sets the route id to use for the route that services the REST API.
296     * <p/>
297     * The route will by default use an auto assigned route id.
298     *
299     * @param apiContextRouteId the route id
300     */
301    public void setApiContextRouteId(String apiContextRouteId) {
302        this.apiContextRouteId = apiContextRouteId;
303    }
304
305    public String getApiContextIdPattern() {
306        return apiContextIdPattern;
307    }
308
309    /**
310     * Sets an CamelContext id pattern to only allow Rest APIs from rest
311     * services within CamelContext's which name matches the pattern.
312     * <p/>
313     * The pattern <tt>#name#</tt> refers to the CamelContext name, to match on
314     * the current CamelContext only. For any other value, the pattern uses the
315     * rules from {@link PatternHelper#matchPattern(String, String)}
316     *
317     * @param apiContextIdPattern the pattern
318     */
319    public void setApiContextIdPattern(String apiContextIdPattern) {
320        this.apiContextIdPattern = apiContextIdPattern;
321    }
322
323    public Boolean getApiContextListing() {
324        return apiContextListing;
325    }
326
327    /**
328     * Sets whether listing of all available CamelContext's with REST services
329     * in the JVM is enabled. If enabled it allows to discover these contexts,
330     * if <tt>false</tt> then only the current CamelContext is in use.
331     */
332    public void setApiContextListing(Boolean apiContextListing) {
333        this.apiContextListing = apiContextListing;
334    }
335
336    public Boolean getApiVendorExtension() {
337        return apiVendorExtension;
338    }
339
340    /**
341     * Whether vendor extension is enabled in the Rest APIs. If enabled then
342     * Camel will include additional information as vendor extension (eg keys
343     * starting with x-) such as route ids, class names etc. Not all 3rd party
344     * API gateways and tools supports vendor-extensions when importing your API
345     * docs.
346     */
347    public void setApiVendorExtension(Boolean apiVendorExtension) {
348        this.apiVendorExtension = apiVendorExtension;
349    }
350
351    public RestHostNameResolver getHostNameResolver() {
352        return hostNameResolver;
353    }
354
355    /**
356     * If no hostname has been explicit configured, then this resolver is used
357     * to compute the hostname the REST service will be using.
358     */
359    public void setHostNameResolver(RestHostNameResolver hostNameResolver) {
360        this.hostNameResolver = hostNameResolver;
361    }
362
363    public RestBindingMode getBindingMode() {
364        return bindingMode;
365    }
366
367    /**
368     * Sets the binding mode to use.
369     * <p/>
370     * The default value is off
371     */
372    public void setBindingMode(RestBindingMode bindingMode) {
373        this.bindingMode = bindingMode;
374    }
375
376    public Boolean getSkipBindingOnErrorCode() {
377        return skipBindingOnErrorCode;
378    }
379
380    /**
381     * Whether to skip binding on output if there is a custom HTTP error code
382     * header. This allows to build custom error messages that do not bind to
383     * json / xml etc, as success messages otherwise will do.
384     */
385    public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) {
386        this.skipBindingOnErrorCode = skipBindingOnErrorCode;
387    }
388
389    public Boolean getClientRequestValidation() {
390        return clientRequestValidation;
391    }
392
393    /**
394     * Whether to enable validation of the client request to check whether the
395     * Content-Type and Accept headers from the client is supported by the
396     * Rest-DSL configuration of its consumes/produces settings.
397     * <p/>
398     * This can be turned on, to enable this check. In case of validation error,
399     * then HTTP Status codes 415 or 406 is returned.
400     * <p/>
401     * The default value is false.
402     */
403    public void setClientRequestValidation(Boolean clientRequestValidation) {
404        this.clientRequestValidation = clientRequestValidation;
405    }
406
407    public Boolean getEnableCORS() {
408        return enableCORS;
409    }
410
411    /**
412     * Whether to enable CORS headers in the HTTP response.
413     * <p/>
414     * The default value is false.
415     */
416    public void setEnableCORS(Boolean enableCORS) {
417        this.enableCORS = enableCORS;
418    }
419
420    public String getJsonDataFormat() {
421        return jsonDataFormat;
422    }
423
424    /**
425     * Name of specific json data format to use. By default json-jackson will be
426     * used. Important: This option is only for setting a custom name of the
427     * data format, not to refer to an existing data format instance.
428     */
429    public void setJsonDataFormat(String jsonDataFormat) {
430        this.jsonDataFormat = jsonDataFormat;
431    }
432
433    public String getXmlDataFormat() {
434        return xmlDataFormat;
435    }
436
437    /**
438     * Name of specific XML data format to use. By default jaxb will be used.
439     * Important: This option is only for setting a custom name of the data
440     * format, not to refer to an existing data format instance.
441     */
442    public void setXmlDataFormat(String xmlDataFormat) {
443        this.xmlDataFormat = xmlDataFormat;
444    }
445
446    public List<RestPropertyDefinition> getComponentProperties() {
447        return componentProperties;
448    }
449
450    /**
451     * Allows to configure as many additional properties for the rest component
452     * in use.
453     */
454    public void setComponentProperties(List<RestPropertyDefinition> componentProperties) {
455        this.componentProperties = componentProperties;
456    }
457
458    public List<RestPropertyDefinition> getEndpointProperties() {
459        return endpointProperties;
460    }
461
462    /**
463     * Allows to configure as many additional properties for the rest endpoint
464     * in use.
465     */
466    public void setEndpointProperties(List<RestPropertyDefinition> endpointProperties) {
467        this.endpointProperties = endpointProperties;
468    }
469
470    public List<RestPropertyDefinition> getConsumerProperties() {
471        return consumerProperties;
472    }
473
474    /**
475     * Allows to configure as many additional properties for the rest consumer
476     * in use.
477     */
478    public void setConsumerProperties(List<RestPropertyDefinition> consumerProperties) {
479        this.consumerProperties = consumerProperties;
480    }
481
482    public List<RestPropertyDefinition> getDataFormatProperties() {
483        return dataFormatProperties;
484    }
485
486    /**
487     * Allows to configure as many additional properties for the data formats in
488     * use. For example set property prettyPrint to true to have json outputted
489     * in pretty mode. The properties can be prefixed to denote the option is
490     * only for either JSON or XML and for either the IN or the OUT. The
491     * prefixes are:
492     * <ul>
493     * <li>json.in.</li>
494     * <li>json.out.</li>
495     * <li>xml.in.</li>
496     * <li>xml.out.</li>
497     * </ul>
498     * For example a key with value "xml.out.mustBeJAXBElement" is only for the
499     * XML data format for the outgoing. A key without a prefix is a common key
500     * for all situations.
501     */
502    public void setDataFormatProperties(List<RestPropertyDefinition> dataFormatProperties) {
503        this.dataFormatProperties = dataFormatProperties;
504    }
505
506    public List<RestPropertyDefinition> getApiProperties() {
507        return apiProperties;
508    }
509
510    /**
511     * Allows to configure as many additional properties for the api
512     * documentation (swagger). For example set property api.title to my cool
513     * stuff
514     */
515    public void setApiProperties(List<RestPropertyDefinition> apiProperties) {
516        this.apiProperties = apiProperties;
517    }
518
519    public List<RestPropertyDefinition> getCorsHeaders() {
520        return corsHeaders;
521    }
522
523    /**
524     * Allows to configure custom CORS headers.
525     */
526    public void setCorsHeaders(List<RestPropertyDefinition> corsHeaders) {
527        this.corsHeaders = corsHeaders;
528    }
529
530    public Boolean getUseXForwardHeaders() {
531        return useXForwardHeaders;
532    }
533
534    /**
535     * Whether to use X-Forward headers for Host and related setting.
536     * <p/>
537     * The default value is true.
538     */
539    public void setUseXForwardHeaders(Boolean useXForwardHeaders) {
540        this.useXForwardHeaders = useXForwardHeaders;
541    }
542
543    // Fluent API
544    // -------------------------------------------------------------------------
545
546    /**
547     * To use a specific Camel rest component (consumer)
548     */
549    public RestConfigurationDefinition component(String componentId) {
550        setComponent(componentId);
551        return this;
552    }
553
554    /**
555     * To use a specific Camel rest API component
556     */
557    public RestConfigurationDefinition apiComponent(String componentId) {
558        setApiComponent(componentId);
559        return this;
560    }
561
562    /**
563     * To use a specific Camel rest component (producer)
564     */
565    public RestConfigurationDefinition producerComponent(String componentId) {
566        setProducerComponent(componentId);
567        return this;
568    }
569
570    /**
571     * To use a specific scheme such as http/https
572     */
573    public RestConfigurationDefinition scheme(String scheme) {
574        setScheme(scheme);
575        return this;
576    }
577
578    /**
579     * To define the host to use, such as 0.0.0.0 or localhost
580     */
581    public RestConfigurationDefinition host(String host) {
582        setHost(host);
583        return this;
584    }
585
586    /**
587     * To define a specific host to use for API documentation (eg swagger)
588     * instead of using a generated API hostname that is relative to the REST
589     * service host.
590     */
591    public RestConfigurationDefinition apiHost(String host) {
592        setApiHost(host);
593        return this;
594    }
595
596    /**
597     * To specify the port number to use for the REST service
598     */
599    public RestConfigurationDefinition port(int port) {
600        setPort("" + port);
601        return this;
602    }
603
604    /**
605     * To specify the port number to use for the REST service
606     */
607    public RestConfigurationDefinition port(String port) {
608        setPort(port);
609        return this;
610    }
611
612    /**
613     * Sets the location of the api document (swagger api) the REST producer
614     * will use to validate the REST uri and query parameters are valid
615     * accordingly to the api document. This requires adding camel-swagger-java
616     * to the classpath, and any miss configuration will let Camel fail on
617     * startup and report the error(s).
618     * <p/>
619     * The location of the api document is loaded from classpath by default, but
620     * you can use <tt>file:</tt> or <tt>http:</tt> to refer to resources to
621     * load from file or http url.
622     */
623    public RestConfigurationDefinition producerApiDoc(String apiDoc) {
624        setProducerApiDoc(apiDoc);
625        return this;
626    }
627
628    /**
629     * Sets a leading context-path the REST services will be using.
630     * <p/>
631     * This can be used when using components such as <tt>camel-servlet</tt>
632     * where the deployed web application is deployed using a context-path. Or
633     * for components such as <tt>camel-jetty</tt> or <tt>camel-netty-http</tt>
634     * that includes a HTTP server.
635     */
636    public RestConfigurationDefinition apiContextPath(String contextPath) {
637        setApiContextPath(contextPath);
638        return this;
639    }
640
641    /**
642     * Sets the route id to use for the route that services the REST API.
643     */
644    public RestConfigurationDefinition apiContextRouteId(String routeId) {
645        setApiContextRouteId(routeId);
646        return this;
647    }
648
649    /**
650     * Sets an CamelContext id pattern to only allow Rest APIs from rest
651     * services within CamelContext's which name matches the pattern.
652     * <p/>
653     * The pattern uses the following rules are applied in this order:
654     * <ul>
655     * <li>exact match, returns true</li>
656     * <li>wildcard match (pattern ends with a * and the name starts with the
657     * pattern), returns true</li>
658     * <li>regular expression match, returns true</li>
659     * <li>otherwise returns false</li>
660     * </ul>
661     */
662    public RestConfigurationDefinition apiContextIdPattern(String pattern) {
663        setApiContextIdPattern(pattern);
664        return this;
665    }
666
667    /**
668     * Sets whether listing of all available CamelContext's with REST services
669     * in the JVM is enabled. If enabled it allows to discover these contexts,
670     * if <tt>false</tt> then only the current CamelContext is in use.
671     */
672    public RestConfigurationDefinition apiContextListing(boolean listing) {
673        setApiContextListing(listing);
674        return this;
675    }
676
677    /**
678     * Whether vendor extension is enabled in the Rest APIs. If enabled then
679     * Camel will include additional information as vendor extension (eg keys
680     * starting with x-) such as route ids, class names etc. Some API tooling
681     * may not support vendor extensions and this option can then be turned off.
682     */
683    public RestConfigurationDefinition apiVendorExtension(boolean vendorExtension) {
684        setApiVendorExtension(vendorExtension);
685        return this;
686    }
687
688    /**
689     * Sets a leading context-path the REST services will be using.
690     * <p/>
691     * This can be used when using components such as <tt>camel-servlet</tt>
692     * where the deployed web application is deployed using a context-path.
693     */
694    public RestConfigurationDefinition contextPath(String contextPath) {
695        setContextPath(contextPath);
696        return this;
697    }
698
699    /**
700     * To specify the hostname resolver
701     */
702    public RestConfigurationDefinition hostNameResolver(RestHostNameResolver hostNameResolver) {
703        setHostNameResolver(hostNameResolver);
704        return this;
705    }
706
707    /**
708     * To specify the binding mode
709     */
710    public RestConfigurationDefinition bindingMode(RestBindingMode bindingMode) {
711        setBindingMode(bindingMode);
712        return this;
713    }
714
715    /**
716     * To specify the binding mode
717     */
718    public RestConfigurationDefinition bindingMode(String bindingMode) {
719        setBindingMode(RestBindingMode.valueOf(bindingMode.toLowerCase()));
720        return this;
721    }
722
723    /**
724     * To specify whether to skip binding output if there is a custom HTTP error
725     * code
726     */
727    public RestConfigurationDefinition skipBindingOnErrorCode(boolean skipBindingOnErrorCode) {
728        setSkipBindingOnErrorCode(skipBindingOnErrorCode);
729        return this;
730    }
731
732    /**
733     * Whether to enable validation of the client request to check whether the
734     * Content-Type and Accept headers from the client is supported by the
735     * Rest-DSL configuration of its consumes/produces settings.
736     */
737    public RestConfigurationDefinition clientRequestValidation(boolean clientRequestValidation) {
738        setClientRequestValidation(clientRequestValidation);
739        return this;
740    }
741
742    /**
743     * To specify whether to enable CORS which means Camel will automatic
744     * include CORS in the HTTP headers in the response.
745     */
746    public RestConfigurationDefinition enableCORS(boolean enableCORS) {
747        setEnableCORS(enableCORS);
748        return this;
749    }
750
751    /**
752     * To use a specific json data format
753     * <p/>
754     * <b>Important:</b> This option is only for setting a custom name of the
755     * data format, not to refer to an existing data format instance.
756     *
757     * @param name name of the data format to
758     *            {@link org.apache.camel.CamelContext#resolveDataFormat(java.lang.String)
759     *            resolve}
760     */
761    public RestConfigurationDefinition jsonDataFormat(String name) {
762        setJsonDataFormat(name);
763        return this;
764    }
765
766    /**
767     * To use a specific XML data format
768     * <p/>
769     * <b>Important:</b> This option is only for setting a custom name of the
770     * data format, not to refer to an existing data format instance.
771     *
772     * @param name name of the data format to
773     *            {@link org.apache.camel.CamelContext#resolveDataFormat(java.lang.String)
774     *            resolve}
775     */
776    public RestConfigurationDefinition xmlDataFormat(String name) {
777        setXmlDataFormat(name);
778        return this;
779    }
780
781    /**
782     * For additional configuration options on component level
783     * <p/>
784     * The value can use <tt>#</tt> to refer to a bean to lookup in the
785     * registry.
786     */
787    public RestConfigurationDefinition componentProperty(String key, String value) {
788        RestPropertyDefinition prop = new RestPropertyDefinition();
789        prop.setKey(key);
790        prop.setValue(value);
791        getComponentProperties().add(prop);
792        return this;
793    }
794
795    /**
796     * For additional configuration options on endpoint level
797     * <p/>
798     * The value can use <tt>#</tt> to refer to a bean to lookup in the
799     * registry.
800     */
801    public RestConfigurationDefinition endpointProperty(String key, String value) {
802        RestPropertyDefinition prop = new RestPropertyDefinition();
803        prop.setKey(key);
804        prop.setValue(value);
805        getEndpointProperties().add(prop);
806        return this;
807    }
808
809    /**
810     * For additional configuration options on consumer level
811     * <p/>
812     * The value can use <tt>#</tt> to refer to a bean to lookup in the
813     * registry.
814     */
815    public RestConfigurationDefinition consumerProperty(String key, String value) {
816        RestPropertyDefinition prop = new RestPropertyDefinition();
817        prop.setKey(key);
818        prop.setValue(value);
819        getConsumerProperties().add(prop);
820        return this;
821    }
822
823    /**
824     * For additional configuration options on data format level
825     * <p/>
826     * The value can use <tt>#</tt> to refer to a bean to lookup in the
827     * registry.
828     */
829    public RestConfigurationDefinition dataFormatProperty(String key, String value) {
830        RestPropertyDefinition prop = new RestPropertyDefinition();
831        prop.setKey(key);
832        prop.setValue(value);
833        getDataFormatProperties().add(prop);
834        return this;
835    }
836
837    /**
838     * For configuring an api property, such as <tt>api.title</tt>, or
839     * <tt>api.version</tt>.
840     */
841    public RestConfigurationDefinition apiProperty(String key, String value) {
842        RestPropertyDefinition prop = new RestPropertyDefinition();
843        prop.setKey(key);
844        prop.setValue(value);
845        getApiProperties().add(prop);
846        return this;
847    }
848
849    /**
850     * For configuring CORS headers
851     */
852    public RestConfigurationDefinition corsHeaderProperty(String key, String value) {
853        RestPropertyDefinition prop = new RestPropertyDefinition();
854        prop.setKey(key);
855        prop.setValue(value);
856        getCorsHeaders().add(prop);
857        return this;
858    }
859
860    /**
861     * Shortcut for setting the {@code Access-Control-Allow-Credentials} header.
862     */
863    public RestConfigurationDefinition corsAllowCredentials(boolean corsAllowCredentials) {
864        return corsHeaderProperty("Access-Control-Allow-Credentials", String.valueOf(corsAllowCredentials));
865    }
866
867    /**
868     * To specify whether to use X-Forward headers for Host and related setting
869     */
870    public RestConfigurationDefinition useXForwardHeaders(boolean useXForwardHeaders) {
871        setUseXForwardHeaders(useXForwardHeaders);
872        return this;
873    }
874
875    // Implementation
876    // -------------------------------------------------------------------------
877
878    /**
879     * Creates a {@link org.apache.camel.spi.RestConfiguration} instance based
880     * on the definition
881     *
882     * @param context the camel context
883     * @return the configuration
884     * @throws Exception is thrown if error creating the configuration
885     */
886    public RestConfiguration asRestConfiguration(CamelContext context) throws Exception {
887        RestConfiguration answer = new RestConfiguration();
888        if (component != null) {
889            answer.setComponent(CamelContextHelper.parseText(context, component));
890        }
891        if (apiComponent != null) {
892            answer.setApiComponent(CamelContextHelper.parseText(context, apiComponent));
893        }
894        if (producerComponent != null) {
895            answer.setProducerComponent(CamelContextHelper.parseText(context, producerComponent));
896        }
897        if (scheme != null) {
898            answer.setScheme(CamelContextHelper.parseText(context, scheme));
899        }
900        if (host != null) {
901            answer.setHost(CamelContextHelper.parseText(context, host));
902        }
903        if (useXForwardHeaders != null) {
904            answer.setUseXForwardHeaders(useXForwardHeaders);
905        }
906        if (apiHost != null) {
907            answer.setApiHost(CamelContextHelper.parseText(context, apiHost));
908        }
909        if (port != null) {
910            answer.setPort(CamelContextHelper.parseInteger(context, port));
911        }
912        if (producerApiDoc != null) {
913            answer.setProducerApiDoc(CamelContextHelper.parseText(context, producerApiDoc));
914        }
915        if (apiContextPath != null) {
916            answer.setApiContextPath(CamelContextHelper.parseText(context, apiContextPath));
917        }
918        if (apiContextRouteId != null) {
919            answer.setApiContextRouteId(CamelContextHelper.parseText(context, apiContextRouteId));
920        }
921        if (apiContextIdPattern != null) {
922            // special to allow #name# to refer to itself
923            if ("#name#".equals(apiComponent)) {
924                answer.setApiContextIdPattern(context.getName());
925            } else {
926                answer.setApiContextIdPattern(CamelContextHelper.parseText(context, apiContextIdPattern));
927            }
928        }
929        if (apiContextListing != null) {
930            answer.setApiContextListing(apiContextListing);
931        }
932        if (apiVendorExtension != null) {
933            answer.setApiVendorExtension(apiVendorExtension);
934        }
935        if (contextPath != null) {
936            answer.setContextPath(CamelContextHelper.parseText(context, contextPath));
937        }
938        if (hostNameResolver != null) {
939            answer.setHostNameResolver(hostNameResolver.name());
940        }
941        if (bindingMode != null) {
942            answer.setBindingMode(bindingMode.name());
943        }
944        if (skipBindingOnErrorCode != null) {
945            answer.setSkipBindingOnErrorCode(skipBindingOnErrorCode);
946        }
947        if (clientRequestValidation != null) {
948            answer.setClientRequestValidation(clientRequestValidation);
949        }
950        if (enableCORS != null) {
951            answer.setEnableCORS(enableCORS);
952        }
953        if (jsonDataFormat != null) {
954            answer.setJsonDataFormat(jsonDataFormat);
955        }
956        if (xmlDataFormat != null) {
957            answer.setXmlDataFormat(xmlDataFormat);
958        }
959        if (!componentProperties.isEmpty()) {
960            Map<String, Object> props = new HashMap<>();
961            for (RestPropertyDefinition prop : componentProperties) {
962                String key = prop.getKey();
963                String value = CamelContextHelper.parseText(context, prop.getValue());
964                props.put(key, value);
965            }
966            answer.setComponentProperties(props);
967        }
968        if (!endpointProperties.isEmpty()) {
969            Map<String, Object> props = new HashMap<>();
970            for (RestPropertyDefinition prop : endpointProperties) {
971                String key = prop.getKey();
972                String value = CamelContextHelper.parseText(context, prop.getValue());
973                props.put(key, value);
974            }
975            answer.setEndpointProperties(props);
976        }
977        if (!consumerProperties.isEmpty()) {
978            Map<String, Object> props = new HashMap<>();
979            for (RestPropertyDefinition prop : consumerProperties) {
980                String key = prop.getKey();
981                String value = CamelContextHelper.parseText(context, prop.getValue());
982                props.put(key, value);
983            }
984            answer.setConsumerProperties(props);
985        }
986        if (!dataFormatProperties.isEmpty()) {
987            Map<String, Object> props = new HashMap<>();
988            for (RestPropertyDefinition prop : dataFormatProperties) {
989                String key = prop.getKey();
990                String value = CamelContextHelper.parseText(context, prop.getValue());
991                props.put(key, value);
992            }
993            answer.setDataFormatProperties(props);
994        }
995        if (!apiProperties.isEmpty()) {
996            Map<String, Object> props = new HashMap<>();
997            for (RestPropertyDefinition prop : apiProperties) {
998                String key = prop.getKey();
999                String value = CamelContextHelper.parseText(context, prop.getValue());
1000                props.put(key, value);
1001            }
1002            answer.setApiProperties(props);
1003        }
1004        if (!corsHeaders.isEmpty()) {
1005            Map<String, String> props = new HashMap<>();
1006            for (RestPropertyDefinition prop : corsHeaders) {
1007                String key = prop.getKey();
1008                String value = CamelContextHelper.parseText(context, prop.getValue());
1009                props.put(key, value);
1010            }
1011            answer.setCorsHeaders(props);
1012        }
1013        return answer;
1014    }
1015
1016}