| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.camel.component.rest; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.camel.CamelContext; |
| import org.apache.camel.CamelContextAware; |
| import org.apache.camel.Consumer; |
| import org.apache.camel.Endpoint; |
| import org.apache.camel.Exchange; |
| import org.apache.camel.Producer; |
| import org.apache.camel.Route; |
| import org.apache.camel.RuntimeCamelException; |
| import org.apache.camel.Service; |
| import org.apache.camel.ServiceStatus; |
| import org.apache.camel.StatefulService; |
| import org.apache.camel.StaticService; |
| import org.apache.camel.spi.RestConfiguration; |
| import org.apache.camel.spi.RestRegistry; |
| import org.apache.camel.support.LifecycleStrategySupport; |
| import org.apache.camel.support.service.ServiceSupport; |
| import org.apache.camel.util.ObjectHelper; |
| |
| public class DefaultRestRegistry extends ServiceSupport implements StaticService, RestRegistry, CamelContextAware { |
| |
| private CamelContext camelContext; |
| private final Map<Consumer, RestService> registry = new LinkedHashMap<>(); |
| private transient Producer apiProducer; |
| |
| public void addRestService(Consumer consumer, String url, String baseUrl, String basePath, String uriTemplate, String method, |
| String consumes, String produces, String inType, String outType, String routeId, String description) { |
| RestServiceEntry entry = new RestServiceEntry(consumer, url, baseUrl, basePath, uriTemplate, method, consumes, produces, inType, outType, routeId, description); |
| registry.put(consumer, entry); |
| } |
| |
| public void removeRestService(Consumer consumer) { |
| registry.remove(consumer); |
| } |
| |
| @Override |
| public List<RestRegistry.RestService> listAllRestServices() { |
| return new ArrayList<>(registry.values()); |
| } |
| |
| @Override |
| public int size() { |
| return registry.size(); |
| } |
| |
| @Override |
| public String apiDocAsJson() { |
| // see if there is a rest-api endpoint which would be the case if rest api-doc has been explicit enabled |
| if (apiProducer == null) { |
| Endpoint restApiEndpoint = null; |
| Endpoint restEndpoint = null; |
| for (Map.Entry<String, Endpoint> entry : camelContext.getEndpointMap().entrySet()) { |
| String uri = entry.getKey(); |
| if (uri.startsWith("rest-api:")) { |
| restApiEndpoint = entry.getValue(); |
| break; |
| } else if (restEndpoint == null && uri.startsWith("rest:")) { |
| restEndpoint = entry.getValue(); |
| } |
| } |
| |
| if (restApiEndpoint == null && restEndpoint != null) { |
| // no rest-api has been explicit enabled, then we need to create it first |
| RestEndpoint rest = (RestEndpoint) restEndpoint; |
| String componentName = rest.getProducerComponentName(); |
| |
| if (componentName != null) { |
| RestConfiguration config = camelContext.getRestConfiguration(componentName, true); |
| String apiComponent = config.getApiComponent() != null ? config.getApiComponent() : RestApiEndpoint.DEFAULT_API_COMPONENT_NAME; |
| String path = config.getApiContextPath() != null ? config.getApiContextPath() : "api-doc"; |
| restApiEndpoint = camelContext.getEndpoint(String.format("rest-api:%s/%s?componentName=%s&apiComponentName=%s&contextIdPattern=#name#", |
| path, camelContext.getName(), componentName, apiComponent)); |
| } |
| } |
| |
| if (restApiEndpoint != null) { |
| // reuse the producer to avoid creating it |
| try { |
| apiProducer = restApiEndpoint.createProducer(); |
| camelContext.addService(apiProducer, true); |
| } catch (Exception e) { |
| throw RuntimeCamelException.wrapRuntimeCamelException(e); |
| } |
| } |
| } |
| |
| if (apiProducer != null) { |
| try { |
| Exchange dummy = apiProducer.getEndpoint().createExchange(); |
| apiProducer.process(dummy); |
| |
| String json = dummy.hasOut() ? dummy.getOut().getBody(String.class) : dummy.getIn().getBody(String.class); |
| return json; |
| } catch (Exception e) { |
| throw RuntimeCamelException.wrapRuntimeCamelException(e); |
| } |
| } |
| |
| return null; |
| } |
| |
| public CamelContext getCamelContext() { |
| return camelContext; |
| } |
| |
| public void setCamelContext(CamelContext camelContext) { |
| this.camelContext = camelContext; |
| } |
| |
| @Override |
| protected void doStart() throws Exception { |
| ObjectHelper.notNull(camelContext, "camelContext", this); |
| // add a lifecycle so we can keep track when consumers is being removed, so we can unregister them from our registry |
| camelContext.addLifecycleStrategy(new RemoveRestServiceLifecycleStrategy()); |
| } |
| |
| @Override |
| protected void doStop() throws Exception { |
| registry.clear(); |
| } |
| |
| /** |
| * Represents a rest service |
| */ |
| private final class RestServiceEntry implements RestService { |
| |
| private final Consumer consumer; |
| private final String url; |
| private final String baseUrl; |
| private final String basePath; |
| private final String uriTemplate; |
| private final String method; |
| private final String consumes; |
| private final String produces; |
| private final String inType; |
| private final String outType; |
| private final String routeId; |
| private final String description; |
| |
| private RestServiceEntry(Consumer consumer, String url, String baseUrl, String basePath, String uriTemplate, String method, |
| String consumes, String produces, String inType, String outType, String routeId, String description) { |
| this.consumer = consumer; |
| this.url = url; |
| this.baseUrl = baseUrl; |
| this.basePath = basePath; |
| this.uriTemplate = uriTemplate; |
| this.method = method; |
| this.consumes = consumes; |
| this.produces = produces; |
| this.inType = inType; |
| this.outType = outType; |
| this.routeId = routeId; |
| this.description = description; |
| } |
| |
| public Consumer getConsumer() { |
| return consumer; |
| } |
| |
| public String getUrl() { |
| return url; |
| } |
| |
| public String getBaseUrl() { |
| return baseUrl; |
| } |
| |
| public String getBasePath() { |
| return basePath; |
| } |
| |
| public String getUriTemplate() { |
| return uriTemplate; |
| } |
| |
| public String getMethod() { |
| return method; |
| } |
| |
| public String getConsumes() { |
| return consumes; |
| } |
| |
| public String getProduces() { |
| return produces; |
| } |
| |
| public String getInType() { |
| return inType; |
| } |
| |
| public String getOutType() { |
| return outType; |
| } |
| |
| public String getState() { |
| // must use String type to be sure remote JMX can read the attribute without requiring Camel classes. |
| ServiceStatus status = null; |
| if (consumer instanceof StatefulService) { |
| status = ((StatefulService) consumer).getStatus(); |
| } |
| // if no status exists then its stopped |
| if (status == null) { |
| status = ServiceStatus.Stopped; |
| } |
| return status.name(); |
| } |
| |
| public String getRouteId() { |
| return routeId; |
| } |
| |
| public String getDescription() { |
| return description; |
| } |
| } |
| |
| /** |
| * A {@link org.apache.camel.spi.LifecycleStrategy} that keeps track when a {@link Consumer} is removed |
| * and automatic un-register it from this REST registry. |
| */ |
| private final class RemoveRestServiceLifecycleStrategy extends LifecycleStrategySupport { |
| |
| @Override |
| public void onServiceRemove(CamelContext context, Service service, Route route) { |
| super.onServiceRemove(context, service, route); |
| |
| // if its a consumer then de-register it from the rest registry |
| if (service instanceof Consumer) { |
| removeRestService((Consumer) service); |
| } |
| } |
| } |
| } |