blob: 0595eba5b146ffd4a712cec493268b4572d03c79 [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.generator.swagger;
import java.io.IOException;
import java.time.Instant;
import java.util.function.Function;
import java.util.stream.Collector;
import javax.annotation.Generated;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import io.swagger.models.Info;
import io.swagger.models.Swagger;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.util.ObjectHelper;
import static org.apache.camel.util.StringHelper.notEmpty;
/**
* Generates Java source code
*/
public abstract class RestDslSourceCodeGenerator<T> extends RestDslGenerator<RestDslSourceCodeGenerator<T>> {
static final String DEFAULT_CLASS_NAME = "RestDslRoute";
static final String DEFAULT_PACKAGE_NAME = "rest.dsl.generated";
private static final String DEFAULT_INDENT = " ";
private Function<Swagger, String> classNameGenerator = RestDslSourceCodeGenerator::generateClassName;
private Instant generated = Instant.now();
private String indent = DEFAULT_INDENT;
private Function<Swagger, String> packageNameGenerator = RestDslSourceCodeGenerator::generatePackageName;
private boolean sourceCodeTimestamps;
RestDslSourceCodeGenerator(final Swagger swagger) {
super(swagger);
}
public abstract void generate(T destination) throws IOException;
public RestDslSourceCodeGenerator<T> withClassName(final String className) {
notEmpty(className, "className");
this.classNameGenerator = (s) -> className;
return this;
}
public RestDslSourceCodeGenerator<T> withIndent(final String indent) {
this.indent = ObjectHelper.notNull(indent, "indent");
return this;
}
public RestDslSourceCodeGenerator<T> withoutSourceCodeTimestamps() {
sourceCodeTimestamps = false;
return this;
}
public RestDslSourceCodeGenerator<T> withPackageName(final String packageName) {
notEmpty(packageName, "packageName");
this.packageNameGenerator = (s) -> packageName;
return this;
}
public RestDslSourceCodeGenerator<T> withSourceCodeTimestamps() {
sourceCodeTimestamps = true;
return this;
}
MethodSpec generateConfigureMethod(final Swagger swagger) {
final MethodSpec.Builder configure = MethodSpec.methodBuilder("configure").addModifiers(Modifier.PUBLIC)
.returns(void.class).addJavadoc("Defines Apache Camel routes using REST DSL fluent API.\n");
final MethodBodySourceCodeEmitter emitter = new MethodBodySourceCodeEmitter(configure);
if (restComponent != null) {
configure.addCode("\n");
configure.addCode("restConfiguration().component(\"" + restComponent + "\")");
if (restContextPath != null) {
configure.addCode(".contextPath(\"" + restContextPath + "\")");
}
if (ObjectHelper.isNotEmpty(apiContextPath)) {
configure.addCode(".apiContextPath(\"" + apiContextPath + "\")");
}
configure.addCode(";\n\n");
}
final PathVisitor<MethodSpec> restDslStatement = new PathVisitor<>(swagger.getBasePath(), emitter, filter, destinationGenerator());
swagger.getPaths().forEach(restDslStatement::visit);
return emitter.result();
}
Instant generated() {
return generated;
}
JavaFile generateSourceCode() {
final MethodSpec methodSpec = generateConfigureMethod(swagger);
final String classNameToUse = classNameGenerator.apply(swagger);
final AnnotationSpec.Builder generatedAnnotation = AnnotationSpec.builder(Generated.class).addMember("value",
"$S", getClass().getName());
if (sourceCodeTimestamps) {
generatedAnnotation.addMember("date", "$S", generated());
}
TypeSpec.Builder builder = TypeSpec.classBuilder(classNameToUse).superclass(RouteBuilder.class)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(methodSpec)
.addAnnotation(generatedAnnotation.build())
.addJavadoc("Generated from Swagger specification by Camel REST DSL generator.\n");
if (springComponent) {
final AnnotationSpec.Builder springAnnotation = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.stereotype.Component"));
builder.addAnnotation(springAnnotation.build());
}
TypeSpec generatedRouteBuilder = builder.build();
final String packageNameToUse = packageNameGenerator.apply(swagger);
return JavaFile.builder(packageNameToUse, generatedRouteBuilder).indent(indent).build();
}
RestDslSourceCodeGenerator<T> withGeneratedTime(final Instant generated) {
this.generated = generated;
return this;
}
static String generateClassName(final Swagger swagger) {
final Info info = swagger.getInfo();
if (info == null) {
return DEFAULT_CLASS_NAME;
}
final String title = info.getTitle();
if (title == null) {
return DEFAULT_CLASS_NAME;
}
final String className = title.chars().filter(Character::isJavaIdentifierPart).filter(c -> c < 'z').boxed()
.collect(Collector.of(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append,
StringBuilder::toString));
if (className.isEmpty() || !Character.isJavaIdentifierStart(className.charAt(0))) {
return DEFAULT_CLASS_NAME;
}
return className;
}
static String generatePackageName(final Swagger swagger) {
final String host = swagger.getHost();
if (ObjectHelper.isNotEmpty(host)) {
final StringBuilder packageName = new StringBuilder();
final String hostWithoutPort = host.replaceFirst(":.*", "");
if ("localhost".equalsIgnoreCase(hostWithoutPort)) {
return DEFAULT_PACKAGE_NAME;
}
final String[] parts = hostWithoutPort.split("\\.");
for (int i = parts.length - 1; i >= 0; i--) {
packageName.append(parts[i]);
if (i != 0) {
packageName.append('.');
}
}
return packageName.toString();
}
return DEFAULT_PACKAGE_NAME;
}
}