Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

yaml-loader: add support for OnException #337

Merged
merged 1 commit into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class FromStepParser implements StartStepParser {
public ProcessorDefinition<?> toStartProcessor(Context context) {
final FromStepDefinition definition = context.node(FromStepDefinition.class);
final String uri = definition.getEndpointUri();
final RouteDefinition route = new RouteDefinition().from(uri);
final RouteDefinition route = context.builder().from(uri);

// as this is a start converter, steps are mandatory
StepParserSupport.notNull(definition.steps, "steps");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* 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.k.loader.yaml.parser;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonAlias;
import org.apache.camel.k.annotation.yaml.YAMLNodeDefinition;
import org.apache.camel.k.annotation.yaml.YAMLStepParser;
import org.apache.camel.k.loader.yaml.model.Step;
import org.apache.camel.k.loader.yaml.spi.ProcessorStepParser;
import org.apache.camel.k.loader.yaml.spi.StartStepParser;
import org.apache.camel.k.loader.yaml.spi.StepParserSupport;
import org.apache.camel.model.ExpressionSubElementDefinition;
import org.apache.camel.model.OnExceptionDefinition;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RedeliveryPolicyDefinition;
import org.apache.camel.model.WhenDefinition;
import org.apache.camel.model.language.ConstantExpression;
import org.apache.camel.model.language.ExpressionDefinition;
import org.apache.camel.reifier.OnExceptionReifier;

import static org.apache.camel.util.ObjectHelper.ifNotEmpty;

@YAMLStepParser("on-exception")
public class OnExceptionStepParser implements StartStepParser, ProcessorStepParser {
@SuppressWarnings("unchecked")
@Override
public ProcessorDefinition<?> toStartProcessor(Context context) {
final Definition definition = context.node(Definition.class);
final OnExceptionDefinition onException = context.builder().onException();

if (definition.exceptions == null) {
definition.exceptions = List.of(Exception.class.getName());
}

onException.setExceptions(definition.exceptions);
onException.setRouteScoped(false);

mapToOnException(context, definition, onException);

return StepParserSupport.convertSteps(
context,
onException,
definition.steps);
}

@Override
public ProcessorDefinition<?> toProcessor(Context context) {
final Definition definition = context.node(Definition.class);
final OnExceptionDefinition onException = new OnExceptionDefinition();

if (definition.exceptions == null) {
definition.exceptions = List.of(Exception.class.getName());
}

onException.setExceptions(definition.exceptions);
onException.setRouteScoped(true);

mapToOnException(context, definition, onException);

return StepParserSupport.convertSteps(
context,
onException,
definition.steps);
}

private static void mapToOnException(Context context, Definition definition, OnExceptionDefinition onException) {
ifNotEmpty(definition.retryWhile, onException::setRetryWhile);
ifNotEmpty(definition.handled, onException::setHandled);
ifNotEmpty(definition.continued, onException::setContinued);
ifNotEmpty(definition.continued, onException::setContinued);
ifNotEmpty(definition.redeliveryPolicyType, onException::setRedeliveryPolicyType);
ifNotEmpty(definition.redeliveryPolicyRef, onException::setRedeliveryPolicyRef);
ifNotEmpty(definition.onRedeliveryRef, onException::setOnRedeliveryRef);
ifNotEmpty(definition.onExceptionOccurredRef, onException::setOnExceptionOccurredRef);
ifNotEmpty(definition.useOriginalMessage, val -> onException.setUseOriginalMessage(Boolean.toString(val)));
ifNotEmpty(definition.useOriginalBody, val -> onException.setUseOriginalBody(Boolean.toString(val)));

if (definition.onWhen != null) {
StepParserSupport.notNull(definition.onWhen.steps, "onWhen.steps");

StepParserSupport.convertSteps(
context,
definition.onWhen,
definition.onWhen.steps
);

onException.setOnWhen(definition.onWhen);
}
}

@YAMLNodeDefinition(reifiers = OnExceptionReifier.class)
public static final class Definition {
public List<Step> steps;

@JsonAlias("exceptions")
public List<String> exceptions;

@JsonAlias({"when", "on-when"})
public When onWhen;
@JsonAlias("retry-while")
public ExpressionElement retryWhile;
@JsonAlias("handled")
public MaybeBooleanExpressionElement handled;
@JsonAlias("continued")
public MaybeBooleanExpressionElement continued;

@JsonAlias("redelivery-policy")
public RedeliveryPolicyDefinition redeliveryPolicyType;
@JsonAlias("redelivery-policy-ref")
public String redeliveryPolicyRef;

@JsonAlias("on-redelivery-ref")
public String onRedeliveryRef;
@JsonAlias("on-exception-occurred-ref")
public String onExceptionOccurredRef;
@JsonAlias("use-original-message")
public boolean useOriginalMessage;
@JsonAlias("use-original-body")
public boolean useOriginalBody;

public static final class When extends WhenDefinition implements HasExpression {
public List<Step> steps;
}

public static final class ExpressionElement extends ExpressionSubElementDefinition implements HasExpression {
@Override
public void setExpression(ExpressionDefinition expressionDefinition) {
super.setExpressionType(expressionDefinition);
}

@Override
public ExpressionDefinition getExpression() {
return super.getExpressionType();
}
}

public static final class MaybeBooleanExpressionElement extends ExpressionSubElementDefinition implements HasExpression {
public MaybeBooleanExpressionElement() {
}

public MaybeBooleanExpressionElement(boolean argument) {
setExpression(new ConstantExpression(Boolean.toString(argument)));
}

@Override
public void setExpression(ExpressionDefinition expressionDefinition) {
super.setExpressionType(expressionDefinition);
}

@Override
public ExpressionDefinition getExpression() {
return super.getExpressionType();
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public ProcessorDefinition<?> toStartProcessor(Context context) {
StepParserSupport.notNull(definition.verb, "verb");
StepParserSupport.notNull(definition.steps, "steps");

RestDefinition rest = new RestDefinition().verb(definition.verb, definition.uri);
RestDefinition rest = context.builder().rest().verb(definition.verb, definition.uri);

ObjectHelper.ifNotEmpty(definition.apiDocs, rest::apiDocs);
ObjectHelper.ifNotEmpty(definition.enableCORS, rest::enableCORS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
public interface StartStepParser extends StepParser {
/**
* @param context
* @return
*/
ProcessorDefinition<?> toStartProcessor(Context context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.CamelContext;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.HasCamelContext;
import org.apache.camel.util.ObjectHelper;

Expand All @@ -35,20 +36,24 @@ public interface StepParser {
*/
class Context implements HasCamelContext {
private final ObjectMapper mapper;
private final CamelContext camelContext;
private final RouteBuilder builder;
private final JsonNode node;
private final Resolver resolver;

public Context(CamelContext camelContext, ObjectMapper mapper, JsonNode node, Resolver resolver) {
this.camelContext = camelContext;
public Context(RouteBuilder builder, ObjectMapper mapper, JsonNode node, Resolver resolver) {
this.builder = builder;
this.mapper = mapper;
this.node = node;
this.resolver = ObjectHelper.notNull(resolver, "resolver");
}

@Override
public CamelContext getCamelContext() {
return camelContext;
return builder.getContext();
}

public RouteBuilder builder() {
return builder;
}

public JsonNode node() {
Expand All @@ -75,7 +80,7 @@ public <T> T node(Class<T> type) {
}

public <T extends StepParser> T lookup(Class<T> type, String stepId) {
StepParser parser = resolver.resolve(camelContext, stepId);
StepParser parser = resolver.resolve(builder.getContext(), stepId);
if (type.isInstance(parser)) {
return type.cast(parser);
}
Expand All @@ -85,7 +90,7 @@ public <T extends StepParser> T lookup(Class<T> type, String stepId) {

public static Context of(Context context, JsonNode step) {
return new Context(
context.camelContext,
context.builder,
context.mapper,
step,
context.resolver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

Expand All @@ -31,7 +30,6 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.k.Runtime;
import org.apache.camel.k.Source;
Expand All @@ -40,11 +38,6 @@
import org.apache.camel.k.loader.yaml.model.Step;
import org.apache.camel.k.loader.yaml.spi.StartStepParser;
import org.apache.camel.k.loader.yaml.spi.StepParser;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;

@Loader("yaml")
public class YamlSourceLoader implements SourceLoader {
Expand Down Expand Up @@ -94,41 +87,12 @@ final RouteBuilder builder(InputStream is) {
@Override
public void configure() throws Exception {
final StepParser.Resolver resolver = StepParser.Resolver.caching(new YamlStepResolver());
final CamelContext camelContext = getContext();
final List<RouteDefinition> routes = new ArrayList<>();
final List<RestDefinition> rests = new ArrayList<>();

try (is) {
for (Step step : mapper.readValue(is, Step[].class)) {
final StepParser.Context context = new StepParser.Context(camelContext, mapper, step.node, resolver);
final ProcessorDefinition<?> root = StartStepParser.invoke(context, step.id);

if (root == null) {
throw new IllegalStateException("No route definition");
}
if (!(root instanceof RouteDefinition)) {
throw new IllegalStateException("Root definition should be of type RouteDefinition");
}

RouteDefinition r = (RouteDefinition) root;
if (r.getRestDefinition() == null) {
routes.add(r);
} else {
rests.add(r.getRestDefinition());
}
}

if (!routes.isEmpty()) {
RoutesDefinition definition = new RoutesDefinition();
definition.setRoutes(routes);

setRouteCollection(definition);
}
if (!rests.isEmpty()) {
RestsDefinition definition = new RestsDefinition();
definition.setRests(rests);

setRestCollection(definition);
StartStepParser.invoke(
new StepParser.Context(this, mapper, step.node, resolver),
step.id);
}
}
}
Expand Down
Loading