blob: 9aaa45eaeb77e9f40977e138dd27bb63a8b89c3b [file] [log] [blame]
/*
* 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.knative;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.component.knative.ce.CloudEventProcessor;
import org.apache.camel.component.knative.ce.CloudEventProcessors;
import org.apache.camel.component.knative.spi.CloudEvent;
import org.apache.camel.component.knative.spi.Knative;
import org.apache.camel.component.knative.spi.KnativeEnvironment;
import org.apache.camel.processor.Pipeline;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
import org.apache.camel.support.DefaultEndpoint;
import org.apache.camel.support.PropertyBindingSupport;
/**
* This component allows to interact with KNative events.
*/
@UriEndpoint(
firstVersion = "3.0.0",
scheme = "knative",
syntax = "knative:type/name",
title = "Knative",
label = "cloud,eventing")
public class KnativeEndpoint extends DefaultEndpoint {
@UriPath(description = "The Knative type")
private final Knative.Type type;
@UriPath(description = "The Knative name")
private final String name;
@UriParam
private KnativeConfiguration configuration;
private final CloudEventProcessor cloudEvent;
public KnativeEndpoint(String uri, KnativeComponent component, Knative.Type type, String name, KnativeConfiguration configuration) {
super(uri, component);
this.type = type;
this.name = name;
this.configuration = configuration;
this.cloudEvent = CloudEventProcessors.fromSpecVersion(configuration.getCloudEventsSpecVersion());
}
@Override
public KnativeComponent getComponent() {
return (KnativeComponent) super.getComponent();
}
@Override
public Producer createProducer() throws Exception {
final KnativeEnvironment.KnativeServiceDefinition service = lookupServiceDefinition(Knative.EndpointKind.sink);
final Processor ceProcessor = cloudEvent.producer(this, service);
final Processor ceConverter = new KnativeConversionProcessor(configuration.isJsonSerializationEnabled());
final Producer producer = getComponent().getTransport().createProducer(this, service);
PropertyBindingSupport.build()
.withCamelContext(getCamelContext())
.withProperties(configuration.getTransportOptions())
.withRemoveParameters(false)
.withTarget(producer)
.bind();
return new KnativeProducer(this, ceProcessor, ceConverter, e -> e.getMessage().removeHeader("Host"), producer);
}
@Override
public Consumer createConsumer(Processor processor) throws Exception {
final KnativeEnvironment.KnativeServiceDefinition service = lookupServiceDefinition(Knative.EndpointKind.source);
final Processor ceProcessor = cloudEvent.consumer(this, service);
final Processor pipeline = Pipeline.newInstance(getCamelContext(), ceProcessor, processor);
final Consumer consumer = getComponent().getTransport().createConsumer(this, service, pipeline);
PropertyBindingSupport.build()
.withCamelContext(getCamelContext())
.withProperties(configuration.getTransportOptions())
.withRemoveParameters(false)
.withTarget(consumer)
.bind();
configureConsumer(consumer);
return consumer;
}
@Override
public boolean isSingleton() {
return true;
}
public Knative.Type getType() {
return type;
}
public String getName() {
return name;
}
public void setConfiguration(KnativeConfiguration configuration) {
this.configuration = configuration;
}
public KnativeConfiguration getConfiguration() {
return configuration;
}
KnativeEnvironment.KnativeServiceDefinition lookupServiceDefinition(Knative.EndpointKind endpointKind) {
String serviceName = configuration.getServiceName();
//
// look-up service definition by service name first then if not found try to look it up by using
// "default" as a service name. For channels and endpoints, the service name can be derived from
// the endpoint uri but for events it is not possible so default should always be there for events
// unless the service name is define as an endpoint option.
//
Optional<KnativeEnvironment.KnativeServiceDefinition> service = lookupServiceDefinition(serviceName, endpointKind);
if (!service.isPresent()) {
service = lookupServiceDefinition("default", endpointKind);
}
if (!service.isPresent()) {
throw new IllegalArgumentException(String.format("Unable to find a service definition for %s/%s/%s", type, serviceName, endpointKind));
}
Map<String, String> metadata = new HashMap<>();
metadata.putAll(service.get().getMetadata());
for (Map.Entry<String, Object> entry: configuration.getFilters().entrySet()) {
String key = entry.getKey();
Object val = entry.getValue();
if (val instanceof String) {
if (!key.startsWith(Knative.KNATIVE_FILTER_PREFIX)) {
key = Knative.KNATIVE_FILTER_PREFIX + key;
}
metadata.put(key, (String)val);
}
}
for (Map.Entry<String, Object> entry: configuration.getCeOverride().entrySet()) {
String key = entry.getKey();
Object val = entry.getValue();
if (val instanceof String) {
if (!key.startsWith(Knative.KNATIVE_CE_OVERRIDE_PREFIX)) {
key = Knative.KNATIVE_CE_OVERRIDE_PREFIX + key;
}
metadata.put(key, (String)val);
}
}
if (service.get().getType() == Knative.Type.event) {
metadata.put(Knative.KNATIVE_EVENT_TYPE, serviceName);
metadata.put(Knative.KNATIVE_FILTER_PREFIX + cloudEvent.cloudEvent().mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http(), serviceName);
}
return new KnativeEnvironment.KnativeServiceDefinition(
service.get().getType(),
service.get().getName(),
service.get().getHost(),
service.get().getPort(),
metadata
);
}
Optional<KnativeEnvironment.KnativeServiceDefinition> lookupServiceDefinition(String name, Knative.EndpointKind endpointKind) {
return this.configuration.getEnvironment()
.lookup(this.type, name)
.filter(s -> {
final String type = s.getMetadata().get(Knative.CAMEL_ENDPOINT_KIND);
final String apiv = s.getMetadata().get(Knative.KNATIVE_API_VERSION);
final String kind = s.getMetadata().get(Knative.KNATIVE_KIND);
if (!Objects.equals(endpointKind.name(), type)) {
return false;
}
if (configuration.getApiVersion() != null && !Objects.equals(apiv, configuration.getApiVersion())) {
return false;
}
if (configuration.getKind() != null && !Objects.equals(kind, configuration.getKind())) {
return false;
}
return true;
})
.findFirst();
}
}