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.component.rest;
018
019import java.util.Map;
020import java.util.Set;
021
022import org.apache.camel.Component;
023import org.apache.camel.Consumer;
024import org.apache.camel.NoSuchBeanException;
025import org.apache.camel.Processor;
026import org.apache.camel.Producer;
027import org.apache.camel.impl.DefaultEndpoint;
028import org.apache.camel.spi.RestConfiguration;
029import org.apache.camel.spi.RestConsumerFactory;
030import org.apache.camel.spi.UriEndpoint;
031import org.apache.camel.spi.UriParam;
032import org.apache.camel.util.HostUtils;
033import org.apache.camel.util.ObjectHelper;
034
035@UriEndpoint(scheme = "rest")
036public class RestEndpoint extends DefaultEndpoint {
037
038    @UriParam
039    private String method;
040    @UriParam
041    private String path;
042    @UriParam
043    private String uriTemplate;
044    @UriParam
045    private String consumes;
046    @UriParam
047    private String produces;
048    @UriParam
049    private String componentName;
050    @UriParam
051    private String inType;
052    @UriParam
053    private String outType;
054    @UriParam
055    private String routeId;
056    @UriParam
057    private String description;
058
059    private Map<String, Object> parameters;
060
061    public RestEndpoint(String endpointUri, RestComponent component) {
062        super(endpointUri, component);
063    }
064
065    @Override
066    public RestComponent getComponent() {
067        return (RestComponent) super.getComponent();
068    }
069
070    public String getMethod() {
071        return method;
072    }
073
074    public void setMethod(String method) {
075        this.method = method;
076    }
077
078    public String getPath() {
079        return path;
080    }
081
082    public void setPath(String path) {
083        this.path = path;
084    }
085
086    public String getUriTemplate() {
087        return uriTemplate;
088    }
089
090    public void setUriTemplate(String uriTemplate) {
091        this.uriTemplate = uriTemplate;
092    }
093
094    public String getConsumes() {
095        return consumes;
096    }
097
098    public void setConsumes(String consumes) {
099        this.consumes = consumes;
100    }
101
102    public String getProduces() {
103        return produces;
104    }
105
106    public void setProduces(String produces) {
107        this.produces = produces;
108    }
109
110    public String getComponentName() {
111        return componentName;
112    }
113
114    public void setComponentName(String componentName) {
115        this.componentName = componentName;
116    }
117
118    public String getInType() {
119        return inType;
120    }
121
122    public void setInType(String inType) {
123        this.inType = inType;
124    }
125
126    public String getOutType() {
127        return outType;
128    }
129
130    public void setOutType(String outType) {
131        this.outType = outType;
132    }
133
134    public String getRouteId() {
135        return routeId;
136    }
137
138    public void setRouteId(String routeId) {
139        this.routeId = routeId;
140    }
141
142    public String getDescription() {
143        return description;
144    }
145
146    public void setDescription(String description) {
147        this.description = description;
148    }
149
150    public Map<String, Object> getParameters() {
151        return parameters;
152    }
153
154    public void setParameters(Map<String, Object> parameters) {
155        this.parameters = parameters;
156    }
157
158    @Override
159    public Producer createProducer() throws Exception {
160        throw new UnsupportedOperationException("Producer not supported");
161    }
162
163    @Override
164    public Consumer createConsumer(Processor processor) throws Exception {
165        RestConsumerFactory factory = null;
166
167        if (getComponentName() != null) {
168            Object comp = getCamelContext().getRegistry().lookupByName(getComponentName());
169            if (comp != null && comp instanceof RestConsumerFactory) {
170                factory = (RestConsumerFactory) comp;
171            } else {
172                comp = getCamelContext().getComponent(getComponentName());
173                if (comp != null && comp instanceof RestConsumerFactory) {
174                    factory = (RestConsumerFactory) comp;
175                }
176            }
177
178            if (factory == null) {
179                if (comp != null) {
180                    throw new IllegalArgumentException("Component " + getComponentName() + " is not a RestConsumerFactory");
181                } else {
182                    throw new NoSuchBeanException(getComponentName(), RestConsumerFactory.class.getName());
183                }
184            }
185        }
186
187        // try all components
188        if (factory == null) {
189            for (String name : getCamelContext().getComponentNames()) {
190                Component comp = getCamelContext().getComponent(name);
191                if (comp != null && comp instanceof RestConsumerFactory) {
192                    factory = (RestConsumerFactory) comp;
193                    break;
194                }
195            }
196        }
197
198        // lookup in registry
199        if (factory == null) {
200            Set<RestConsumerFactory> factories = getCamelContext().getRegistry().findByType(RestConsumerFactory.class);
201            if (factories != null && factories.size() == 1) {
202                factory = factories.iterator().next();
203            }
204        }
205
206        if (factory != null) {
207            Consumer consumer = factory.createConsumer(getCamelContext(), processor, getMethod(), getPath(), getUriTemplate(), getConsumes(), getProduces(), getParameters());
208            configureConsumer(consumer);
209
210            // if no explicit port/host configured, then use port from rest configuration
211            String scheme = "http";
212            String host = "";
213            int port = 80;
214
215            RestConfiguration config = getCamelContext().getRestConfiguration();
216            if (config.getScheme() != null) {
217                scheme = config.getScheme();
218            }
219            if (config.getHost() != null) {
220                host = config.getHost();
221            }
222            int num = config.getPort();
223            if (num > 0) {
224                port = num;
225            }
226
227            // if no explicit hostname set then resolve the hostname
228            if (ObjectHelper.isEmpty(host)) {
229                if (config.getRestHostNameResolver() == RestConfiguration.RestHostNameResolver.localHostName) {
230                    host = HostUtils.getLocalHostName();
231                } else if (config.getRestHostNameResolver() == RestConfiguration.RestHostNameResolver.localIp) {
232                    host = HostUtils.getLocalIp();
233                }
234            }
235
236
237            // calculate the url to the rest service
238            String path = getPath();
239            if (!path.startsWith("/")) {
240                path = "/" + path;
241            }
242
243            // there may be an optional context path configured to help Camel calculate the correct urls for the REST services
244            // this may be needed when using camel-serlvet where we cannot get the actual context-path or port number of the servlet engine
245            // during init of the servlet
246            String contextPath = config.getContextPath();
247            if (contextPath != null) {
248                if (!contextPath.startsWith("/")) {
249                    path = "/" + contextPath + path;
250                } else {
251                    path = contextPath + path;
252                }
253            }
254
255            String baseUrl = scheme + "://" + host + (port != 80 ? ":" + port : "") + path;
256
257            String url = baseUrl;
258            if (uriTemplate != null) {
259                // make sure to avoid double slashes
260                if (uriTemplate.startsWith("/")) {
261                    url = url + uriTemplate;
262                } else {
263                    url = url + "/" + uriTemplate;
264                }
265            }
266
267            // add to rest registry so we can keep track of them, we will remove from the registry when the consumer is removed
268            // the rest registry will automatic keep track when the consumer is removed,
269            // and un-register the REST service from the registry
270            getCamelContext().getRestRegistry().addRestService(consumer, url, baseUrl, getPath(), getUriTemplate(), getMethod(),
271                    getConsumes(), getProduces(), getInType(), getOutType(), getRouteId(), getDescription());
272            return consumer;
273        } else {
274            throw new IllegalStateException("Cannot find RestConsumerFactory in Registry or as a Component to use");
275        }
276    }
277
278    @Override
279    public boolean isSingleton() {
280        return true;
281    }
282
283    @Override
284    public boolean isLenientProperties() {
285        return true;
286    }
287}