diff --git a/Jenkinsfile.split b/Jenkinsfile.split
index bde284048d..bae2205498 100644
--- a/Jenkinsfile.split
+++ b/Jenkinsfile.split
@@ -18,6 +18,7 @@ properties([
booleanParam(name: 'runUnstableTests', defaultValue: true, description: "Whether to run tests in failing group."),
booleanParam(name: 'runPerformanceTests', defaultValue: false, description: "Whether to run performance tests."),
booleanParam(name: 'runClusterTests', defaultValue: false, description: "Whether to run cluster tests."),
+ booleanParam(name: 'useOpenApiTestClient',defaultValue: false, description: "Whether to use an autogenerated OpenAPI OkHTTP 3 based REST client for the tests."),
booleanParam(name: 'runDeploy', defaultValue: false, description: "Whether to run the deploy steps."),
booleanParam(name: 'runDeployTesting', defaultValue: false, description: "Whether to run the testing deploy steps."),
booleanParam(name: 'runDocker', defaultValue: false, description: "Whether to run the docker steps."),
@@ -68,19 +69,19 @@ final def testPart(partName, current, branches) {
// prior to starting the tests, start the docker containers with the db and the testdb-manager
sh 'docker login -u $repoUsername -p $repoPassword docker.gentics.com'
if (Boolean.valueOf(params.testMaria)) {
- sh "mvn -pl :mesh-database-connector-mariadb docker:start -Dskip.mariadb.tests=${noMariadb} "
+ sh "mvn -pl :mesh-database-connector-mariadb docker:start -Dskip.mariadb.tests=${noMariadb} "
}
// run the tests
- withEnv(["TESTCONTAINERS_RYUK_DISABLED=true", "MESH_CONSISTENCY_CHECKS=" + (Boolean.valueOf(params.consistencyChecks) ? "true" : "false"), "MAVEN_OPTS=-Xmx1g -XX:MaxMetaspaceSize=128m "]) {
+ withEnv(["TESTCONTAINERS_RYUK_DISABLED=true", "MESH_CONSISTENCY_CHECKS=" + (Boolean.valueOf(params.consistencyChecks) ? "true" : "false"), "MAVEN_OPTS=-Xmx1g -XX:MaxMetaspaceSize=128m ", "MESH_REST_CLIENT_CLASS=" + (Boolean.valueOf(params.useOpenApiTestClient) ? "com.gentics.mesh.test.openapi.OpenAPIMeshRestClient" : "")]) {
sh ".jenkins/run-splits.sh includes-${postfix} ${jacoco} ${partName} ${partId}"
}
} finally {
// finally stop the docker containers
if (Boolean.valueOf(params.testMaria)) {
- sh "mvn -pl :mesh-database-connector-mariadb docker:stop -Dskip.mariadb.tests=${noMariadb} "
+ sh "mvn -pl :mesh-database-connector-mariadb docker:stop -Dskip.mariadb.tests=${noMariadb} "
+ }
}
}
- }
stash name: "jacoco" + current, includes: "**/jacoco-partial.exec", allowEmpty: true
} finally {
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/*.xml'])
@@ -216,9 +217,9 @@ stage("Setup Build Environment") {
}
try {
withCredentials([usernamePassword(credentialsId: 'docker.gentics.com', usernameVariable: 'repoUsername', passwordVariable: 'repoPassword'),usernamePassword(credentialsId: 'gentics.gpg', usernameVariable: 'gpgKeyName', passwordVariable: 'gpgKeyPass')]) {
- withEnv(["TESTCONTAINERS_RYUK_DISABLED=true", "MESH_CONSISTENCY_CHECKS=" + (Boolean.valueOf(params.consistencyChecks) ? "true" : "false")]) {
+ withEnv(["TESTCONTAINERS_RYUK_DISABLED=true", "MESH_CONSISTENCY_CHECKS=" + (Boolean.valueOf(params.consistencyChecks) ? "true" : "false"), "MESH_REST_CLIENT_CLASS=" + (Boolean.valueOf(params.useOpenApiTestClient) ? "com.gentics.mesh.test.openapi.OpenAPIMeshRestClient" : "")]) {
sh "mvn -fae -Dsurefire.excludedGroups=com.gentics.mesh.test.category.FailingTests,com.gentics.mesh.test.category.ClusterTests -Dmaven.javadoc.skip=true -Dskip.cluster.tests=true -Dmaven.test.failure.ignore=true -Dmesh.container.image.prefix=docker.gentics.com/ -Dskip.mariadb.tests=${noMariadb} -Dskip.hsqlmemory.tests=${noHsqldb} -B -U -e test"
- }
+ }
}
} finally {
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/*.xml'])
diff --git a/api/src/main/java/com/gentics/mesh/etc/config/Format.java b/api/src/main/java/com/gentics/mesh/etc/config/Format.java
new file mode 100644
index 0000000000..1733c377a5
--- /dev/null
+++ b/api/src/main/java/com/gentics/mesh/etc/config/Format.java
@@ -0,0 +1,49 @@
+package com.gentics.mesh.etc.config;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * OpenAPI output format
+ */
+public enum Format {
+ /**
+ * Yaml
+ */
+ YAML(0),
+ /**
+ * JSON
+ */
+ JSON(1);
+
+ private final int level;
+
+ private Format(int level) {
+ this.level = level;
+ }
+
+ /**
+ * Get the filtering int value.
+ *
+ * @return
+ */
+ public int getLevel() {
+ return level;
+ }
+
+ /**
+ * Safe parse string value
+ *
+ * @param format
+ * @param defaultValue
+ * @return
+ */
+ public static Format parse(String format, Format defaultValue) {
+ if (StringUtils.isNotBlank(format)) {
+ switch (format.toUpperCase()) {
+ case "YAML": return YAML;
+ case "JSON": return JSON;
+ }
+ }
+ return defaultValue;
+ }
+}
diff --git a/api/src/main/java/com/gentics/mesh/etc/config/MeshOptions.java b/api/src/main/java/com/gentics/mesh/etc/config/MeshOptions.java
index 32c56ddafc..fb1414691e 100644
--- a/api/src/main/java/com/gentics/mesh/etc/config/MeshOptions.java
+++ b/api/src/main/java/com/gentics/mesh/etc/config/MeshOptions.java
@@ -37,6 +37,7 @@ public abstract class MeshOptions implements Option {
public static final String MESH_CLUSTER_INIT_ENV = "MESH_CLUSTER_INIT";
public static final String MESH_LOCK_PATH_ENV = "MESH_LOCK_PATH";
public static final String MESH_LIVE_PATH_ENV = "MESH_LIVE_PATH";
+ public static final String MESH_SERVE_OPENAPI_ENV = "MESH_SERVE_OPENAPI";
public static final String MESH_START_IN_READ_ONLY_ENV = "MESH_START_IN_READ_ONLY";
public static final String MESH_INITIAL_ADMIN_PASSWORD_ENV = "MESH_INITIAL_ADMIN_PASSWORD";
public static final String MESH_INITIAL_ADMIN_PASSWORD_FORCE_RESET_ENV = "MESH_INITIAL_ADMIN_PASSWORD_FORCE_RESET";
@@ -152,6 +153,10 @@ public abstract class MeshOptions implements Option {
@EnvironmentVariable(name = MESH_MIGRATION_TRIGGER_INTERVAL, description = "Override the migration trigger interval")
private long migrationTriggerInterval = DEFAULT_MIGRATION_TRIGGER_INTERVAL;
+ @JsonProperty(required = false)
+ @EnvironmentVariable(name = MESH_SERVE_OPENAPI_ENV, description = "Serve OpenAPI specification under `/openapi*` endpoints. Default: true")
+ private boolean serveOpenApi = true;
+
@JsonProperty(required = true)
@JsonPropertyDescription("GraphQL options.")
private GraphQLOptions graphQLOptions = new GraphQLOptions();
@@ -272,7 +277,6 @@ public MeshOptions setMonitoringOptions(MonitoringConfig monitoringOptions) {
return this;
}
-
/**
* Get the graphql options
* @return graphql options
@@ -544,6 +548,15 @@ public MeshOptions setPluginUseHttp2(boolean pluginUseHttp2) {
return this;
}
+ public boolean isServeOpenApi() {
+ return serveOpenApi;
+ }
+
+ @Setter
+ public void setServeOpenApi(boolean serveOpenApi) {
+ this.serveOpenApi = serveOpenApi;
+ }
+
@JsonIgnore
public abstract NativeQueryFiltering getNativeQueryFiltering();
@@ -608,4 +621,24 @@ public void validate(MeshOptions options) {
}
public abstract boolean hasDatabaseLevelCache();
+
+ /**
+ * Get default OpenAPI spec version
+ *
+ * @return
+ */
+ public abstract Version getDefaultOpenAPIVersion();
+
+ /**
+ * Get default OpenAPI spec format
+ *
+ * @return
+ */
+ public abstract Format getDefaultOpenAPIFormat();
+
+ /**
+ * Get the comma separated list of plugin, that should provide no API info. Can be null or empty.
+ * @return
+ */
+ public abstract String getNoApiInfoPlugins();
}
diff --git a/api/src/main/java/com/gentics/mesh/etc/config/Version.java b/api/src/main/java/com/gentics/mesh/etc/config/Version.java
new file mode 100644
index 0000000000..79cab7a007
--- /dev/null
+++ b/api/src/main/java/com/gentics/mesh/etc/config/Version.java
@@ -0,0 +1,69 @@
+package com.gentics.mesh.etc.config;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * OpenAPI specification version
+ */
+public enum Version {
+
+ /**
+ * v3.0
+ */
+ V30(0),
+ /**
+ * v3.1
+ */
+ V31(1);
+
+ private final int level;
+
+ private Version(int level) {
+ this.level = level;
+ }
+
+ /**
+ * Get the filtering int value.
+ *
+ * @return
+ */
+ public int getLevel() {
+ return level;
+ }
+
+ /**
+ * Safe parse string value
+ *
+ * @param version
+ * @param defaultValue
+ * @return
+ */
+ public static Version parse(String version, Version defaultValue) {
+ if (StringUtils.isNotBlank(version)) {
+ switch (version.toUpperCase()) {
+ case "V30":
+ case "3.0":
+ return V30;
+ case "V31":
+ case "3.1":
+ return V31;
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Pretty print the version
+ *
+ * @return
+ */
+ public String pretty() {
+ switch(this) {
+ case V30:
+ return "3.0";
+ case V31:
+ return "3.1";
+ }
+ return null;
+ }
+}
diff --git a/bom/pom.xml b/bom/pom.xml
index c97c5e7888..cdf78425b4 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -47,6 +47,8 @@
4.3.1
2.7.3
1.15.5
+ 0.0.1-SNAPSHOT
+ 5.3.0
@@ -108,6 +110,11 @@
commons-lang3
3.18.0
+
+ com.gentics
+ vertx-openapi
+ ${vertx.openapi.version}
+
commons-io
commons-io
@@ -133,7 +140,12 @@
com.squareup.okhttp3
okhttp-jvm
- 5.3.0
+ ${okhttp.version}
+
+
+ com.squareup.okhttp3
+ logging-interceptor
+ ${okhttp.version}
@@ -172,7 +184,7 @@
com.google.code.gson
gson
- 2.8.9
+ 2.10.1
@@ -808,9 +820,9 @@
3.2.0
- jakarta.persistence
- jakarta.persistence-api
- 3.2.0
+ jakarta.persistence
+ jakarta.persistence-api
+ 3.2.0
com.squareup.inject
@@ -833,9 +845,9 @@
${hazelcast-hibernate.version}
- org.hibernate.orm
- hibernate-jcache
- ${hibernate.version}
+ org.hibernate.orm
+ hibernate-jcache
+ ${hibernate.version}
org.hibernate.orm
diff --git a/changelog/src/changelog/entries/2026/03/8685.GPU-2196.enhancement b/changelog/src/changelog/entries/2026/03/8685.GPU-2196.enhancement
new file mode 100644
index 0000000000..1a360ad8e5
--- /dev/null
+++ b/changelog/src/changelog/entries/2026/03/8685.GPU-2196.enhancement
@@ -0,0 +1 @@
+REST API: Along with existing RAML API definition, it is now possible to generate an OpenAPI (aka Swagger) specification for the Mesh REST API. For that, an endpoint `/openapi.yaml` has been provided.
\ No newline at end of file
diff --git a/common/src/main/java/com/gentics/mesh/rest/impl/InternalEndpointRouteImpl.java b/common/src/main/java/com/gentics/mesh/rest/impl/InternalEndpointRouteImpl.java
index bb32e051fb..5ba44c649d 100644
--- a/common/src/main/java/com/gentics/mesh/rest/impl/InternalEndpointRouteImpl.java
+++ b/common/src/main/java/com/gentics/mesh/rest/impl/InternalEndpointRouteImpl.java
@@ -1,50 +1,21 @@
package com.gentics.mesh.rest.impl;
import static com.gentics.mesh.core.rest.error.Errors.error;
-import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON;
-import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON_UTF8;
-import static io.vertx.core.http.HttpMethod.DELETE;
-import static io.vertx.core.http.HttpMethod.POST;
-import static io.vertx.core.http.HttpMethod.PUT;
-import static org.apache.commons.lang3.StringUtils.isEmpty;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.codehaus.jettison.json.JSONObject;
-import org.raml.model.MimeType;
-import org.raml.model.Response;
-import org.raml.model.parameter.FormParameter;
-import org.raml.model.parameter.Header;
-import org.raml.model.parameter.QueryParameter;
-import org.raml.model.parameter.UriParameter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.gentics.mesh.core.db.Database;
import com.gentics.mesh.core.endpoint.admin.LocalConfigApi;
import com.gentics.mesh.core.rest.MeshEvent;
-import com.gentics.mesh.core.rest.common.RestModel;
import com.gentics.mesh.json.JsonUtil;
-import com.gentics.mesh.parameter.ParameterProvider;
import com.gentics.mesh.rest.InternalEndpointRoute;
-import com.google.common.collect.ImmutableSet;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Handler;
-import io.vertx.core.http.HttpMethod;
-import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.PlatformHandler;
@@ -52,448 +23,40 @@
/**
* @see InternalEndpointRoute
*/
-public class InternalEndpointRouteImpl implements InternalEndpointRoute {
-
- private static final Logger log = LoggerFactory.getLogger(InternalEndpointRoute.class);
-
- private static final Map, String> SCHEMA_CACHE = new ConcurrentHashMap<>();
-
- private static final Set mutatingMethods = ImmutableSet.of(POST, PUT, DELETE);
-
- private Route route;
-
- private String displayName;
-
- private String description;
-
- /**
- * Uri Parameters which map to the used path segments
- */
- private Map uriParameters = new HashMap<>();
-
- /**
- * Map of example responses for the corresponding status code.
- */
- private Map exampleResponses = new HashMap<>();
-
- private Map> exampleResponseClasses = new HashMap<>();
+public class InternalEndpointRouteImpl extends com.gentics.vertx.openapi.metadata.InternalEndpointRouteImpl implements InternalEndpointRoute {
- private Set events = new HashSet<>();
-
- private String[] traits = new String[] {};
-
- private HashMap exampleRequestMap = null;
-
- private Class extends RestModel> exampleRequestClass = null;
-
- private String pathRegex;
-
- private HttpMethod method;
-
- private String ramlPath;
-
- private final Set consumes = new LinkedHashSet<>();
- private final Set produces = new LinkedHashSet<>();
-
- private Map parameters = new HashMap<>();
-
- private Boolean mutating;
+ protected Set events = new HashSet<>();
/**
- * Create a new endpoint wrapper using the provided router to create the wrapped route instance.
+ * Create a new endpoint wrapper using the provided router to create the wrapped
+ * route instance.
*
* @param router
* @param localConfigApi
* @param db
*/
public InternalEndpointRouteImpl(Router router, LocalConfigApi localConfigApi, Database db) {
- this.route = router.route();
+ super(router);
+ setInsecure(false);
ReadOnlyHandler readOnlyHandler = new ReadOnlyHandler(localConfigApi, db);
route.handler(readOnlyHandler);
}
@Override
- public InternalEndpointRoute path(String path) {
- route.path(path);
- return this;
- }
-
- @Override
- public InternalEndpointRoute method(HttpMethod method) {
- if (this.method != null) {
- throw new RuntimeException(
- "The method for the endpoint was already set. The endpoint wrapper currently does not support more than one method per route.");
- }
- this.method = method;
- route.method(method);
- return this;
- }
-
- @Override
- public InternalEndpointRoute pathRegex(String path) {
- this.pathRegex = path;
- route.pathRegex(path);
- return this;
- }
-
- @Override
- public InternalEndpointRoute produces(String contentType) {
- produces.add(contentType);
- route.produces(contentType);
- return this;
- }
-
- @Override
- public InternalEndpointRoute consumes(String contentType) {
- consumes.add(contentType);
- route.consumes(contentType);
- return this;
- }
-
- @Override
- public InternalEndpointRoute order(int order) {
- route.order(order);
- return this;
- }
-
- @Override
- public InternalEndpointRoute last() {
- route.last();
- return this;
- }
-
- @Override
- public InternalEndpointRoute handler(Handler requestHandler) {
- validate();
- route.handler(requestHandler);
- return this;
- }
-
- @Override
- public InternalEndpointRoute subRouter(Router subRouter) {
- validate();
- route.subRouter(subRouter);
- return this;
- }
-
- @Override
- public InternalEndpointRoute validate() {
- if (!produces.isEmpty() && produces.contains(APPLICATION_JSON) && exampleResponses.isEmpty()) {
- throw new RuntimeException("Endpoint {" + getRamlPath() + "} has no example responses.");
- }
- if ((consumes.contains(APPLICATION_JSON) || consumes.contains(APPLICATION_JSON_UTF8)) && exampleRequestMap == null) {
- throw new RuntimeException("Endpoint {" + getRamlPath() + "} has no example request.");
- }
- if (isEmpty(description)) {
- throw new RuntimeException("Endpoint {" + getPath() + "} has no description.");
- }
-
- // Check whether all segments have a description.
- List segments = getNamedSegments();
- for (String segment : segments) {
- if (!getUriParameters().containsKey(segment)) {
- throw new RuntimeException("Missing URI description for path {" + getRamlPath() + "} segment {" + segment + "}");
- }
- }
- return this;
- }
-
- @Override
- public List getNamedSegments() {
- List allMatches = new ArrayList();
- Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(getRamlPath());
- while (m.find()) {
- allMatches.add(m.group().substring(1, m.group().length() - 1));
- }
- return allMatches;
- }
-
- @Override
+ @Deprecated
public InternalEndpointRoute blockingHandler(Handler requestHandler) {
- route.blockingHandler(requestHandler);
- return this;
- }
-
- @Override
- public InternalEndpointRoute blockingHandler(Handler requestHandler, boolean ordered) {
- route.blockingHandler(requestHandler, ordered);
- return this;
- }
-
- @Override
- public InternalEndpointRoute failureHandler(Handler failureHandler) {
- route.failureHandler(failureHandler);
- return this;
- }
-
- @Override
- public InternalEndpointRoute remove() {
- route.remove();
- return this;
- }
-
- @Override
- public InternalEndpointRoute disable() {
- route.disable();
- return this;
- }
-
- @Override
- public InternalEndpointRoute enable() {
- route.enable();
- return this;
- }
-
- @Override
- public InternalEndpointRoute useNormalisedPath(boolean useNormalisedPath) {
- route.useNormalizedPath(useNormalisedPath);
- return this;
- }
-
- @Override
- public String getPath() {
- return route.getPath();
- }
-
- @Override
- public String getRamlPath() {
- if (ramlPath == null) {
- return convertPath(route.getPath());
- }
- return ramlPath;
- }
-
- @Override
- public InternalEndpointRoute displayName(String name) {
- this.displayName = name;
- return this;
- }
-
- @Override
- public InternalEndpointRoute description(String description) {
- this.description = description;
- return this;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- @Override
- public String getDisplayName() {
- return displayName;
- }
-
- @Override
- public InternalEndpointRoute exampleResponse(HttpResponseStatus status, String description, String headerName, String example, String headerDescription) {
- Response response = new Response();
- response.setDescription(description);
- exampleResponses.put(status.code(), response);
- if (headerName != null) {
- Header header = new Header();
- header.setDescription(headerDescription);
- header.setExample(example);
- Map headers = new HashMap<>();
- headers.put(headerName, header);
- response.setHeaders(headers);
- }
- return this;
- }
-
- @Override
- public InternalEndpointRoute exampleResponse(HttpResponseStatus status, String description) {
- return exampleResponse(status, description, null, null, null);
- }
-
- @Override
- public InternalEndpointRoute exampleResponse(HttpResponseStatus status, Object model, String description) {
- Response response = new Response();
- response.setDescription(description);
-
- HashMap map = new HashMap<>();
- response.setBody(map);
-
- MimeType mimeType = new MimeType();
- if (model instanceof RestModel) {
- String json = ((RestModel) model).toJson(false);
- mimeType.setExample(json);
- mimeType.setSchema(getSchema(model.getClass()));
- map.put("application/json", mimeType);
- } else {
- mimeType.setExample(model.toString());
- map.put("text/plain", mimeType);
- }
-
- exampleResponses.put(status.code(), response);
- exampleResponseClasses.put(status.code(), model.getClass());
- return this;
- }
-
- private String getSchema(Class extends Object> clazz) {
- return SCHEMA_CACHE.computeIfAbsent(clazz, JsonUtil::getJsonSchema);
- }
-
- @Override
- public Map> getExampleResponseClasses() {
- return exampleResponseClasses;
- }
-
- @Override
- public InternalEndpointRoute exampleRequest(String bodyText) {
- HashMap bodyMap = new HashMap<>();
- MimeType mimeType = new MimeType();
- mimeType.setExample(bodyText);
- bodyMap.put("text/plain", mimeType);
- this.exampleRequestMap = bodyMap;
- return this;
- }
-
- @Override
- public InternalEndpointRoute exampleRequest(Map> parameters) {
- HashMap bodyMap = new HashMap<>();
- MimeType mimeType = new MimeType();
- mimeType.setFormParameters(parameters);
- bodyMap.put("multipart/form-data", mimeType);
- this.exampleRequestMap = bodyMap;
- return this;
- }
-
- @Override
- public InternalEndpointRoute exampleRequest(RestModel model) {
- HashMap bodyMap = new HashMap<>();
- MimeType mimeType = new MimeType();
- String json = model.toJson(false);
- mimeType.setExample(json);
- mimeType.setSchema(getSchema(model.getClass()));
- bodyMap.put("application/json", mimeType);
- this.exampleRequestMap = bodyMap;
- this.exampleRequestClass = model.getClass();
- return this;
- }
-
- @Override
- public InternalEndpointRoute exampleRequest(JSONObject jsonObject) {
- HashMap bodyMap = new HashMap<>();
- MimeType mimeType = new MimeType();
- String json = jsonObject.toString();
- mimeType.setExample(json);
- bodyMap.put("application/json", mimeType);
- this.exampleRequestMap = bodyMap;
- return this;
- }
-
- @Override
- public InternalEndpointRoute traits(String... traits) {
- this.traits = traits;
- return this;
- }
-
- @Override
- public String[] getTraits() {
- return traits;
- }
-
- @Override
- public Map getExampleResponses() {
- return exampleResponses;
- }
-
- @Override
- public HashMap getExampleRequestMap() {
- return exampleRequestMap;
- }
-
- @Override
- public String getPathRegex() {
- return pathRegex;
- }
-
- @Override
- public HttpMethod getMethod() {
- return method;
- }
-
- @Override
- public Map getQueryParameters() {
- return parameters;
- }
-
- @Override
- public InternalEndpointRoute addQueryParameters(Class extends ParameterProvider> clazz) {
- try {
- ParameterProvider provider = clazz.getConstructor().newInstance();
- parameters.putAll(provider.getRAMLParameters());
- } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
- e.printStackTrace();
- }
- return this;
- }
-
- @Override
- public InternalEndpointRoute addQueryParameter(String name, String description, String example) {
- QueryParameter param = new QueryParameter();
- param.setDescription(description);
- if (example != null) {
- param.setExample(example);
- }
- parameters.put(name, param);
+ super.blockingHandler(requestHandler);
return this;
}
@Override
- public InternalEndpointRoute setRAMLPath(String path) {
- this.ramlPath = path;
- return this;
+ protected String getJsonSchema(JsonSchema schema) {
+ return JsonUtil.getJsonSchema(schema);
}
@Override
- public Map getUriParameters() {
- return uriParameters;
- }
-
- @Override
- public InternalEndpointRoute addUriParameter(String key, String description, String example) {
- UriParameter param = new UriParameter(key);
- param.setDescription(description);
- param.setExample(example);
- uriParameters.put(key, param);
- return this;
- }
-
- @Override
- public int compareTo(InternalEndpointRoute o) {
- return getRamlPath().compareTo(o.getRamlPath());
- }
-
- /**
- * Convert the provided vertx path to a RAML path.
- *
- * @param path
- * @return RAML Path which contains '{}' instead of ':' characters
- */
- private String convertPath(String path) {
- StringBuilder builder = new StringBuilder();
- String[] segments = path.split("/");
- for (int i = 0; i < segments.length; i++) {
- String segment = segments[i];
- if (segment.startsWith(":")) {
- segment = "{" + segment.substring(1) + "}";
- }
- builder.append(segment);
- if (i != segments.length - 1) {
- builder.append("/");
- }
- }
- if (path.endsWith("/")) {
- builder.append("/");
- }
- return builder.toString();
- }
-
- @Override
- public Class extends RestModel> getExampleRequestClass() {
- return exampleRequestClass;
+ protected JsonSchema getJsonSchemaObject(Class> clazz) {
+ return JsonUtil.getJsonSchemaObject(clazz);
}
@Override
@@ -502,34 +65,16 @@ public InternalEndpointRoute events(MeshEvent... events) {
return this;
}
- /**
- * Return list of events for the endpoint.
- *
- * @return
- */
- public Set getEvents() {
- return events;
- }
-
@Override
- public boolean isMutating() {
- return Optional.ofNullable(mutating)
- .orElse(Optional.ofNullable(getMethod())
- .map(mutatingMethods::contains)
- .orElse(false));
- }
-
- @Override
- public InternalEndpointRouteImpl setMutating(Boolean mutating) {
- this.mutating = mutating;
+ public InternalEndpointRoute setInsecure(boolean insecure) {
+ if (insecure) {
+ setSecuritySchemes(Collections.emptyList());
+ } else {
+ setSecuritySchemes(Collections.singletonList("bearerAuth"));
+ }
return this;
}
- @Override
- public Route getRoute() {
- return route;
- }
-
private class ReadOnlyHandler implements PlatformHandler {
private final LocalConfigApi localConfigApi;
diff --git a/common/src/main/java/com/gentics/mesh/router/CustomRouterImpl.java b/common/src/main/java/com/gentics/mesh/router/CustomRouterImpl.java
index fa2f34ad2a..09a1df02a9 100644
--- a/common/src/main/java/com/gentics/mesh/router/CustomRouterImpl.java
+++ b/common/src/main/java/com/gentics/mesh/router/CustomRouterImpl.java
@@ -38,6 +38,7 @@ public CustomRouterImpl(Vertx vertx, RootRouterImpl root) {
*
* @return
*/
+ @Override
public Router getRouter() {
return this.router;
}
diff --git a/common/src/main/java/com/gentics/mesh/router/PluginRouterImpl.java b/common/src/main/java/com/gentics/mesh/router/PluginRouterImpl.java
index a05d945dc8..c33c6de651 100644
--- a/common/src/main/java/com/gentics/mesh/router/PluginRouterImpl.java
+++ b/common/src/main/java/com/gentics/mesh/router/PluginRouterImpl.java
@@ -1,5 +1,6 @@
package com.gentics.mesh.router;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -23,9 +24,9 @@ public class PluginRouterImpl implements PluginRouter {
private static final Logger log = LoggerFactory.getLogger(APIRouterImpl.class);
- private Map pluginRouters = new HashMap<>();
+ private final Map pluginRouters = new HashMap<>();
- private Router router;
+ private final Router router;
/**
* Create a new plugin router.
@@ -73,4 +74,13 @@ public void removeRouter(String name) {
}
}
+ @Override
+ public Map pluginRouters() {
+ return Collections.unmodifiableMap(pluginRouters);
+ }
+
+ @Override
+ public Router getRouter() {
+ return router;
+ }
}
diff --git a/common/src/main/java/com/gentics/mesh/router/ProjectsRouterImpl.java b/common/src/main/java/com/gentics/mesh/router/ProjectsRouterImpl.java
index 75c7d7c139..5d2e13ab58 100644
--- a/common/src/main/java/com/gentics/mesh/router/ProjectsRouterImpl.java
+++ b/common/src/main/java/com/gentics/mesh/router/ProjectsRouterImpl.java
@@ -36,9 +36,9 @@ public class ProjectsRouterImpl implements ProjectsRouter {
private final Vertx vertx;
- private APIRouterImpl apiRouter;
+ private final APIRouterImpl apiRouter;
- private Router router;
+ private final Router router;
public ProjectsRouterImpl(Vertx vertx, APIRouterImpl apiRouter) {
this.vertx = vertx;
@@ -121,4 +121,8 @@ public ProjectRouter projectRouter() {
return projectRouter;
}
+ @Override
+ public Router getRouter() {
+ return router;
+ }
}
diff --git a/common/src/main/java/com/gentics/mesh/router/route/AbstractInternalEndpoint.java b/common/src/main/java/com/gentics/mesh/router/route/AbstractInternalEndpoint.java
index 223224662c..8fa06a1937 100644
--- a/common/src/main/java/com/gentics/mesh/router/route/AbstractInternalEndpoint.java
+++ b/common/src/main/java/com/gentics/mesh/router/route/AbstractInternalEndpoint.java
@@ -141,4 +141,8 @@ protected boolean isOrderedBlockingHandlers() {
return Optional.ofNullable(options).map(MeshOptions::getVertxOptions)
.map(VertxOptions::isOrderedBlockingHandlers).orElse(true);
}
+
+ public MeshOptions getOptions() {
+ return options;
+ }
}
diff --git a/common/src/main/java/com/gentics/mesh/util/MeshOpenAPIv3Generator.java b/common/src/main/java/com/gentics/mesh/util/MeshOpenAPIv3Generator.java
new file mode 100644
index 0000000000..0755667fbc
--- /dev/null
+++ b/common/src/main/java/com/gentics/mesh/util/MeshOpenAPIv3Generator.java
@@ -0,0 +1,97 @@
+package com.gentics.mesh.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import com.gentics.vertx.openapi.OpenAPIv3Generator;
+import com.gentics.vertx.openapi.model.ExtendedSecurityScheme;
+import com.gentics.vertx.openapi.model.Format;
+import com.gentics.vertx.openapi.model.InParameter;
+import com.gentics.vertx.openapi.model.OpenAPIGenerationException;
+
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.Parameter;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.vertx.ext.web.Router;
+
+/**
+ * Overridden OpenAPI v3 generator, adding Mesh specific features.
+ */
+public class MeshOpenAPIv3Generator extends OpenAPIv3Generator {
+
+ protected final ExtendedSecurityScheme securityBearerAuth;
+
+ public MeshOpenAPIv3Generator(String version, List servers,
+ Optional extends Collection> maybePathBlacklist,
+ Optional extends Collection> maybePathWhitelist) {
+ this(version, servers, false, maybePathBlacklist, maybePathWhitelist);
+ }
+
+ public MeshOpenAPIv3Generator(String version, List servers,
+ boolean secureByDefault,
+ Optional extends Collection> maybePathBlacklist,
+ Optional extends Collection> maybePathWhitelist) {
+ super(version, servers, Collections.singletonMap("bearerAuth", new ExtendedSecurityScheme(secureByDefault)), maybePathBlacklist, maybePathWhitelist);
+ securityBearerAuth = security.get("bearerAuth");
+ securityBearerAuth.getScheme().setScheme("bearer");
+ securityBearerAuth.getScheme().setType(SecurityScheme.Type.HTTP);
+ securityBearerAuth.getScheme().setBearerFormat("JWT");
+ }
+
+ /**
+ * Generate the specification using some functional shortcuts.
+ *
+ * @param routers
+ * @param format
+ * @param pretty
+ * @param useVersion31
+ * @return
+ * @throws OpenAPIGenerationException
+ */
+ public String generate(Map routers, Format format, boolean pretty, boolean useVersion31) throws OpenAPIGenerationException {
+ return generate("Gentics Mesh REST API", routers, format, pretty, useVersion31);
+ }
+
+ /**
+ * Generate the specification using some functional shortcuts and an API name.
+ *
+ * @param routers
+ * @param format
+ * @param pretty
+ * @param useVersion31
+ * @return
+ * @throws OpenAPIGenerationException
+ */
+ public String generate(String name, Map routers, Format format, boolean pretty, boolean useVersion31) throws OpenAPIGenerationException {
+ return generate(name, routers, format, pretty, useVersion31,
+ // transform project path item
+ Optional.of((path, item) -> {
+ if (path.contains("/{project}/")) {
+ Parameter projectNameParam = new Parameter().name("project").in(InParameter.PATH.toString()).schema(new Schema().type("string").description("Name of the related project"));
+ item.readOperations().stream()
+ .forEach(o -> o.getParameters().stream().filter(p -> "project".equals(p.getName())).findAny()
+ .ifPresentOrElse(present -> {
+ // already exists, no action
+ }, () -> o.addParametersItem(projectNameParam)));
+ }
+ return path;
+ }),
+ // fill the component model
+ Optional.empty());
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected void postProcess(Context context) {
+ // The JSON schema mapper behaves awfully with the field map, making it unusable.
+ Schema fieldMapSchema = new Schema<>();
+ fieldMapSchema.set$ref("#/components/schemas/AnyJson");
+ context.usedComponents.add("AnyJson");
+ context.openApi.getComponents().addSchemas("FieldMap", fieldMapSchema);
+ super.postProcess(context);
+ }
+}
diff --git a/core/pom.xml b/core/pom.xml
index 1accedbd39..51fdd95dd6 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -192,8 +192,23 @@
com.gentics.mesh
mesh-service-aws-s3-storage
-
+
+ io.swagger.core.v3
+ swagger-core
+ 2.2.20
+
+
+ org.reflections
+ reflections
+ 0.10.2
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 4.0.1
+
+
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java
index 31d8371148..a4d63afed2 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java
@@ -6,6 +6,7 @@
import static io.vertx.core.http.HttpMethod.DELETE;
import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.POST;
+import static io.vertx.core.http.HttpMethod.PUT;
import com.gentics.mesh.auth.MeshAuthChain;
import com.gentics.mesh.context.InternalActionContext;
@@ -65,20 +66,37 @@ protected void addRolePermissionHandler(String uuidParameterName, String uuidPar
crudHandler.handleGrantPermissions(ac, uuid);
}, isOrderedBlockingHandlers());
- InternalEndpointRoute revokePermissionsEndpoint = createRoute();
- revokePermissionsEndpoint.path(path);
- revokePermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
- revokePermissionsEndpoint.method(DELETE);
- revokePermissionsEndpoint.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
- revokePermissionsEndpoint.consumes(APPLICATION_JSON);
- revokePermissionsEndpoint.produces(APPLICATION_JSON);
- revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
- revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
- revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED);
- revokePermissionsEndpoint.blockingHandler(rc -> {
+ InternalEndpointRoute revokePermissionsEndpointStandard = createRoute();
+ revokePermissionsEndpointStandard.path(path);
+ revokePermissionsEndpointStandard.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
+ revokePermissionsEndpointStandard.method(PUT);
+ revokePermissionsEndpointStandard.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
+ revokePermissionsEndpointStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
+ revokePermissionsEndpointStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
+ revokePermissionsEndpointStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointStandard.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = rc.request().getParam(uuidParameterName);
crudHandler.handleRevokePermissions(ac, uuid);
}, isOrderedBlockingHandlers());
+
+ InternalEndpointRoute revokePermissionsEndpointNonStandard = createRoute();
+ revokePermissionsEndpointNonStandard.path(path);
+ revokePermissionsEndpointNonStandard.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
+ revokePermissionsEndpointNonStandard.method(DELETE);
+ revokePermissionsEndpointNonStandard.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
+ revokePermissionsEndpointNonStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
+ revokePermissionsEndpointNonStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
+ revokePermissionsEndpointNonStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointNonStandard.setHidden(true);
+ revokePermissionsEndpointNonStandard.blockingHandler(rc -> {
+ InternalActionContext ac = wrap(rc);
+ String uuid = rc.request().getParam(uuidParameterName);
+ crudHandler.handleRevokePermissions(ac, uuid);
+ }, isOrderedBlockingHandlers());
}
}
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java
index 7f0205317c..4ba89bc66f 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java
@@ -6,6 +6,7 @@
import static io.vertx.core.http.HttpMethod.DELETE;
import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.POST;
+import static io.vertx.core.http.HttpMethod.PUT;
import com.gentics.mesh.auth.MeshAuthChain;
import com.gentics.mesh.cli.BootstrapInitializer;
@@ -67,17 +68,34 @@ protected void addRolePermissionHandler(String uuidParameterName, String uuidPar
crudHandler.handleGrantPermissions(ac, uuid);
}, isOrderedBlockingHandlers());
- InternalEndpointRoute revokePermissionsEndpoint = createRoute();
- revokePermissionsEndpoint.path(path);
- revokePermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
- revokePermissionsEndpoint.method(DELETE);
- revokePermissionsEndpoint.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
- revokePermissionsEndpoint.consumes(APPLICATION_JSON);
- revokePermissionsEndpoint.produces(APPLICATION_JSON);
- revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
- revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
- revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED);
- revokePermissionsEndpoint.blockingHandler(rc -> {
+ InternalEndpointRoute revokePermissionsEndpointNonStandard = createRoute();
+ revokePermissionsEndpointNonStandard.path(path);
+ revokePermissionsEndpointNonStandard.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
+ revokePermissionsEndpointNonStandard.method(DELETE);
+ revokePermissionsEndpointNonStandard.setHidden(true);
+ revokePermissionsEndpointNonStandard.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
+ revokePermissionsEndpointNonStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
+ revokePermissionsEndpointNonStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
+ revokePermissionsEndpointNonStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointNonStandard.blockingHandler(rc -> {
+ InternalActionContext ac = wrap(rc);
+ String uuid = rc.request().getParam(uuidParameterName);
+ crudHandler.handleRevokePermissions(ac, uuid);
+ }, isOrderedBlockingHandlers());
+
+ InternalEndpointRoute revokePermissionsEndpointStandard = createRoute();
+ revokePermissionsEndpointStandard.path(path);
+ revokePermissionsEndpointStandard.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample);
+ revokePermissionsEndpointStandard.method(PUT);
+ revokePermissionsEndpointStandard.description("Revoke permissions on the " + typeDescription + " from multiple roles.");
+ revokePermissionsEndpointStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions));
+ revokePermissionsEndpointStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions.");
+ revokePermissionsEndpointStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointStandard.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = rc.request().getParam(uuidParameterName);
crudHandler.handleRevokePermissions(ac, uuid);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminEndpoint.java
index a6abb4cacb..db7578fb1f 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminEndpoint.java
@@ -9,6 +9,7 @@
import static com.gentics.mesh.example.ExampleUuids.JOB_UUID;
import static com.gentics.mesh.example.ExampleUuids.PLUGIN_1_ID;
import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON;
+import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.vertx.core.http.HttpMethod.DELETE;
import static io.vertx.core.http.HttpMethod.GET;
@@ -28,6 +29,7 @@
import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.parameter.impl.ConsistencyCheckParametersImpl;
import com.gentics.mesh.parameter.impl.JobParametersImpl;
+import com.gentics.mesh.parameter.impl.PagingParametersImpl;
import com.gentics.mesh.rest.InternalEndpointRoute;
import com.gentics.mesh.router.route.AbstractInternalEndpoint;
@@ -138,16 +140,16 @@ protected void addPluginHandler() {
}, isOrderedBlockingHandlers());
InternalEndpointRoute readEndpoint = createRoute();
- readEndpoint.path("/plugins/:uuid");
+ readEndpoint.path("/plugins/:id");
readEndpoint.method(GET);
readEndpoint.description("Loads deployment information for the plugin with the given id.");
readEndpoint.produces(APPLICATION_JSON);
- readEndpoint.addUriParameter("uuid", "Uuid of the plugin.", PLUGIN_1_ID);
+ readEndpoint.addUriParameter("id", "Id of the plugin.", PLUGIN_1_ID);
readEndpoint.exampleResponse(OK, adminExamples.createHelloWorldPluginResponse(), "Plugin response.");
readEndpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
- String uuid = ac.getParameter("uuid");
- pluginHandler.handleRead(ac, uuid);
+ String id = ac.getParameter("id");
+ pluginHandler.handleRead(ac, id);
}, false);
InternalEndpointRoute readAllEndpoint = createRoute();
@@ -156,6 +158,7 @@ protected void addPluginHandler() {
readAllEndpoint.description("Loads deployment information for all deployed plugins.");
readAllEndpoint.produces(APPLICATION_JSON);
readAllEndpoint.exampleResponse(OK, adminExamples.createPluginListResponse(), "Plugin list response.");
+ readAllEndpoint.addQueryParameters(PagingParametersImpl.class);
readAllEndpoint.blockingHandler(rc -> {
pluginHandler.handleReadList(wrap(rc));
}, false);
@@ -271,6 +274,7 @@ protected void addJobHandler() {
deleteJob.method(DELETE);
deleteJob.description("Deletes the job. Note that it is only possible to delete failed jobs");
deleteJob.addUriParameter("jobUuid", "Uuid of the job.", JOB_UUID);
+ deleteJob.exampleResponse(NO_CONTENT, "Job has been deleted.");
deleteJob.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = ac.getParameter("jobUuid");
@@ -281,6 +285,7 @@ protected void addJobHandler() {
processJob.path("/jobs/:jobUuid/process");
processJob.method(POST);
processJob.description("Process the job. Failed jobs will be automatically reset and put in queued state.");
+ processJob.exampleResponse(OK, jobExamples.createJobResponse(), "Job information.");
processJob.addUriParameter("jobUuid", "Uuid of the job.", JOB_UUID);
processJob.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
@@ -292,6 +297,7 @@ protected void addJobHandler() {
resetJob.path("/jobs/:jobUuid/error");
resetJob.method(DELETE);
resetJob.description("Deletes error state from the job. This will make it possible to execute the job once again.");
+ resetJob.exampleResponse(NO_CONTENT, "Job has been reset.");
resetJob.addUriParameter("jobUuid", "Uuid of the job.", JOB_UUID);
resetJob.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
@@ -304,6 +310,8 @@ protected void addDebugInfoHandler() {
InternalEndpointRoute route = createRoute();
route.path("/debuginfo");
route.method(GET);
+ route.produces("*/*");
+ route.exampleResponse(OK, "ZIP file");
route.description("Downloads a zip file of various [debug information](/docs/administration-guide/#debuginfo) files.");
route.addQueryParameter("include", "Information to include. See the [documentation](/docs/administration-guide/#debuginfo) for possible usages.", "-log,consistencyCheck");
route.handler(rc -> debugInfoHandler.handle(rc));
@@ -323,6 +331,8 @@ protected void addRuntimeConfigHandler() {
postRoute.method(POST);
postRoute.setMutating(false);
postRoute.produces(APPLICATION_JSON);
+ postRoute.consumes(APPLICATION_JSON);
+ postRoute.exampleRequest(localConfig.createExample());
postRoute.description("Sets the currently active local configuration of this instance.");
postRoute.exampleResponse(OK, localConfig.createExample(), "The currently active local configuration");
postRoute.handler(rc -> localConfigHandler.handleSetActiveConfig(wrap(rc)));
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminHandler.java
index 04eb2b45c7..eaf0d1da2a 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminHandler.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/AdminHandler.java
@@ -32,7 +32,9 @@
import com.gentics.mesh.core.verticle.handler.WriteLock;
import com.gentics.mesh.distributed.coordinator.Coordinator;
import com.gentics.mesh.distributed.coordinator.MasterServer;
+import com.gentics.mesh.etc.config.Format;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.etc.config.Version;
import com.gentics.mesh.generator.RAMLGenerator;
import com.gentics.mesh.parameter.BackupParameters;
import com.gentics.mesh.router.RouterStorageImpl;
@@ -226,6 +228,22 @@ public MeshServerInfoModel getMeshServerInfoModel(InternalActionContext ac) {
return info;
}
+ /**
+ * Handle a request of generating OpenAPI spec for all the routes. All the necessary parameters will be taken from an action context.
+ *
+ * @param ac internal action context.
+ */
+ public void handleOpenAPIv3(InternalActionContext ac) {
+ handleOpenAPIv3(ac, options.getDefaultOpenAPIFormat(), options.getDefaultOpenAPIVersion());
+ }
+
+ /**
+ * Handle a request of generating OpenAPI spec for all the routes, using the configured format and version.
+ *
+ * @param ac internal action context.
+ */
+ public abstract void handleOpenAPIv3(InternalActionContext ac, Format format, Version version);
+
/**
* Generate and return the RAML of the server.
*
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/HealthEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/HealthEndpoint.java
index a533ec4311..4319d7d6f4 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/HealthEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/HealthEndpoint.java
@@ -11,6 +11,8 @@
import com.gentics.mesh.rest.InternalEndpointRoute;
import com.gentics.mesh.router.route.AbstractInternalEndpoint;
+import io.netty.handler.codec.http.HttpResponseStatus;
+
/**
* Endpoint definition for health / readiness checks
*/
@@ -42,25 +44,31 @@ public String getDescription() {
private void addLive() {
InternalEndpointRoute deployEndpoint = createRoute();
+ deployEndpoint.setInsecure(true);
deployEndpoint.path("/live");
deployEndpoint.method(GET);
deployEndpoint.description("Returns an empty response with status code 200 if Gentics Mesh is alive.");
+ deployEndpoint.exampleResponse(HttpResponseStatus.OK, "Mesh is alive.");
deployEndpoint.handler(rc -> monitoringCrudHandler.handleLive(rc));
}
private void addReady() {
InternalEndpointRoute deployEndpoint = createRoute();
deployEndpoint.path("/ready");
+ deployEndpoint.setInsecure(true);
deployEndpoint.method(GET);
deployEndpoint.description("Returns an empty response with status code 200 if Gentics Mesh is ready. Responds with 503 otherwise.");
+ deployEndpoint.exampleResponse(HttpResponseStatus.OK, "Mesh is ready.");
deployEndpoint.handler(rc -> monitoringCrudHandler.handleReady(rc));
}
private void addWritable() {
InternalEndpointRoute deployEndpoint = createRoute();
deployEndpoint.path("/writable");
+ deployEndpoint.setInsecure(true);
deployEndpoint.method(GET);
deployEndpoint.description("Returns an empty response with status code 200 if Gentics Mesh is writable. Responds with 503 otherwise.");
+ deployEndpoint.exampleResponse(HttpResponseStatus.OK, "Mesh is writable.");
deployEndpoint.handler(rc -> monitoringCrudHandler.handleWritable(rc));
}
}
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/RestInfoEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/RestInfoEndpoint.java
index b43b39984f..233abd9a9a 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/admin/RestInfoEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/admin/RestInfoEndpoint.java
@@ -5,17 +5,17 @@
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.vertx.core.http.HttpMethod.GET;
-import javax.inject.Inject;
-
import com.gentics.mesh.auth.MeshAuthChain;
import com.gentics.mesh.context.InternalActionContext;
import com.gentics.mesh.core.db.Database;
+import com.gentics.mesh.etc.config.Format;
import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.example.RestInfoExamples;
import com.gentics.mesh.rest.InternalEndpointRoute;
import com.gentics.mesh.router.RouterStorage;
import com.gentics.mesh.router.route.AbstractInternalEndpoint;
+import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Vertx;
import io.vertx.ext.web.Router;
@@ -24,13 +24,12 @@
*/
public class RestInfoEndpoint extends AbstractInternalEndpoint {
- private RestInfoExamples examples = new RestInfoExamples();
+ protected RestInfoExamples examples = new RestInfoExamples();
- private AdminHandler adminHandler;
+ protected AdminHandler adminHandler;
- private RouterStorage routerStorage;
+ protected RouterStorage routerStorage;
- @Inject
public RestInfoEndpoint(MeshAuthChain chain, AdminHandler adminHandler, LocalConfigApi localConfigApi, Database db, MeshOptions options) {
super(null, chain, localConfigApi, db, options);
this.adminHandler = adminHandler;
@@ -67,8 +66,27 @@ public void registerEndPoints() {
adminHandler.handleRAML(ac);
}, false);
+ MeshOptions options = getOptions();
+ secure("/openapi." + options.getDefaultOpenAPIFormat().name().toLowerCase());
+ InternalEndpointRoute openapiYml = createRoute();
+ openapiYml.path("/openapi." + options.getDefaultOpenAPIFormat().name().toLowerCase());
+ openapiYml.method(GET);
+ openapiYml.description("Endpoint which provides an OpenAPI v" + options.getDefaultOpenAPIVersion().pretty() + " " + options.getDefaultOpenAPIFormat().name() + " document for all registed endpoints.");
+ openapiYml.displayName("OpenAPI specification");
+ openapiYml.exampleResponse(OK, "Not yet specified");
+ openapiYml.produces(options.getDefaultOpenAPIFormat() == Format.JSON ? APPLICATION_JSON : APPLICATION_YAML);
+ openapiYml.blockingHandler(rc -> {
+ InternalActionContext ac = wrap(rc);
+ if (getOptions().isServeOpenApi()) {
+ adminHandler.handleOpenAPIv3(ac);
+ } else {
+ ac.send(HttpResponseStatus.FORBIDDEN);
+ }
+ }, false);
+
secure("/");
InternalEndpointRoute infoEndpoint = createRoute();
+ infoEndpoint.setInsecure(true);
infoEndpoint.path("/");
infoEndpoint.description("Endpoint which returns version information");
infoEndpoint.displayName("Version Information");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/auth/AuthenticationEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/auth/AuthenticationEndpoint.java
index 79c95fa16b..ecdd6a66e9 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/auth/AuthenticationEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/auth/AuthenticationEndpoint.java
@@ -71,6 +71,7 @@ public void registerEndPoints() {
loginEndpoint.path("/login");
loginEndpoint.method(POST);
loginEndpoint.setMutating(false);
+ loginEndpoint.setInsecure(true);
loginEndpoint.consumes(APPLICATION_JSON);
loginEndpoint.produces(APPLICATION_JSON);
loginEndpoint.description("Login via this dedicated login endpoint.");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java
index ad32b10715..2532d7d6f9 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java
@@ -247,8 +247,8 @@ private void addUpdateHandler() {
updateBranch.consumes(APPLICATION_JSON);
updateBranch.produces(APPLICATION_JSON);
updateBranch.exampleRequest(versioningExamples.createBranchUpdateRequest("Winter Collection Branch"));
- updateBranch.exampleResponse(OK, versioningExamples.createBranchResponse("Winter Collection Branch", false), "Updated branch");
- updateBranch.events(BRANCH_UPDATED);
+ updateBranch.exampleResponse(OK, versioningExamples.createBranchResponse("Winter Collection Branch", false), "Updated or new branch");
+ updateBranch.events(BRANCH_CREATED, BRANCH_UPDATED);
updateBranch.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = rc.request().params().get("branchUuid");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/eventbus/EventbusEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/eventbus/EventbusEndpoint.java
index 96c357303b..95ac0a36de 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/eventbus/EventbusEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/eventbus/EventbusEndpoint.java
@@ -55,9 +55,10 @@ private void addEventBusHandler() {
secureAll();
InternalEndpointRoute endpoint = createRoute();
endpoint.setRAMLPath("/");
+ endpoint.setHidden(true);
endpoint.description("This endpoint provides a sockjs compliant websocket which can be used to interface with the vert.x eventbus.");
- if (!isRamlGeneratorContext()) {
+ if (!isSpecGeneratorContext()) {
SockJSHandlerOptions sockJSoptions = new SockJSHandlerOptions().setHeartbeatInterval(2000);
SockJSHandler handler = SockJSHandler.create(vertx, sockJSoptions);
SockJSBridgeOptions bridgeOptions = new SockJSBridgeOptions();
@@ -91,10 +92,10 @@ private void addEventBusHandler() {
}
/**
- * Returns whether the method is called from during the documentation generation context.
+ * Returns whether the method is called from during the specification generation context.
* @return
*/
- private boolean isRamlGeneratorContext() {
+ private boolean isSpecGeneratorContext() {
return localRouter == null;
}
}
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java
index 95dff5296c..596c115872 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java
@@ -191,14 +191,13 @@ private void addUpdateHandler() {
endpoint.consumes(APPLICATION_JSON);
endpoint.produces(APPLICATION_JSON);
endpoint.exampleRequest(groupExamples.getGroupUpdateRequest("New group name"));
- endpoint.exampleResponse(OK, groupExamples.getGroupResponse1("New group name"), "Updated group.");
- endpoint.events(GROUP_UPDATED);
+ endpoint.exampleResponse(OK, groupExamples.getGroupResponse1("New group name"), "Updated or new group.");
+ endpoint.events(GROUP_CREATED, GROUP_UPDATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = ac.getParameter("groupUuid");
crudHandler.handleUpdate(ac, uuid);
}, isOrderedBlockingHandlers());
-
}
private void addReadHandler() {
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java
index 7120c2efa7..6851bc67e5 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java
@@ -171,8 +171,8 @@ private void addUpdateHandler() {
endpoint.exampleRequest(microschemaExamples.getGeolocationMicroschemaUpdateRequest());
// endpoint.exampleResponse(OK, microschemaExamples.getGeolocationMicroschemaResponse(), "Updated microschema.");
endpoint.exampleResponse(OK, miscExamples.createMessageResponse(), "Migration message.");
- endpoint.description("Update the microschema with the given uuid.");
- endpoint.events(MICROSCHEMA_UPDATED, MICROSCHEMA_MIGRATION_START, MICROSCHEMA_MIGRATION_FINISHED);
+ endpoint.description("Update or create the microschema with the given uuid.");
+ endpoint.events(MICROSCHEMA_UPDATED, MICROSCHEMA_CREATED, MICROSCHEMA_MIGRATION_START, MICROSCHEMA_MIGRATION_FINISHED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = ac.getParameter("microschemaUuid");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/ProjectMicroschemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/ProjectMicroschemaEndpoint.java
index 8cc0e1824a..47e90e2bda 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/ProjectMicroschemaEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/ProjectMicroschemaEndpoint.java
@@ -18,6 +18,8 @@
import com.gentics.mesh.core.db.Database;
import com.gentics.mesh.core.endpoint.admin.LocalConfigApi;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.parameter.impl.GenericParametersImpl;
+import com.gentics.mesh.parameter.impl.PagingParametersImpl;
import com.gentics.mesh.rest.InternalEndpointRoute;
import com.gentics.mesh.router.route.AbstractProjectEndpoint;
@@ -56,6 +58,8 @@ private void addReadHandlers() {
endpoint.path("/");
endpoint.method(GET);
endpoint.produces(APPLICATION_JSON);
+ endpoint.addQueryParameters(PagingParametersImpl.class);
+ endpoint.addQueryParameters(GenericParametersImpl.class);
endpoint.description("Read all microschemas which are assigned to the project.");
endpoint.exampleResponse(OK, microschemaExamples.getMicroschemaListResponse(), "List of assigned microschemas.");
endpoint.handler(rc -> {
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/node/AbstractBinaryUploadHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/node/AbstractBinaryUploadHandler.java
index 0d36e78e0a..3bae414dd2 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/node/AbstractBinaryUploadHandler.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/node/AbstractBinaryUploadHandler.java
@@ -7,6 +7,9 @@
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.apache.commons.lang3.StringUtils.isEmpty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.gentics.mesh.context.InternalActionContext;
import com.gentics.mesh.core.data.HibLanguage;
import com.gentics.mesh.core.data.HibNodeFieldContainer;
@@ -28,8 +31,6 @@
import com.gentics.mesh.etc.config.MeshOptions;
import io.reactivex.Flowable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Base class for binary upload handler and S3 binary upload handler.
@@ -63,19 +64,19 @@ public void handleBinaryCheckResult(InternalActionContext ac, String nodeUuid, S
validateParameter(nodeUuid, "uuid");
validateParameter(fieldName, "fieldName");
- String languageTag = ac.getParameter("lang");
+ String[] languageTag = ac.getLanguageParameters().getLanguages();
- if (isEmpty(languageTag)) {
+ if (languageTag == null || languageTag.length < 1) {
throw error(BAD_REQUEST, "upload_error_no_language");
}
- String nodeVersion = ac.getParameter("version");
+ String nodeVersion = ac.getVersioningParameters().getVersion();
if (isEmpty(nodeVersion)) {
throw error(BAD_REQUEST, "upload_error_no_version");
}
- String checkSecret = ac.getParameter("secret");
+ String checkSecret = ac.getBinaryCheckParameters().getSecret();
if (isEmpty(checkSecret)) {
throw error(BAD_REQUEST, "error_binaryfield_invalid_check_secret", fieldName);
@@ -85,7 +86,7 @@ public void handleBinaryCheckResult(InternalActionContext ac, String nodeUuid, S
(batch, tx) -> {
CommonTx ctx = tx.unwrap();
HibProject project = tx.getProject(ac);
- HibLanguage language = tx.languageDao().findByLanguageTag(project, languageTag);
+ HibLanguage language = tx.languageDao().findByLanguageTag(project, languageTag[0]);
if (language == null) {
throw error(NOT_FOUND, "error_language_not_found", languageTag);
@@ -94,7 +95,7 @@ public void handleBinaryCheckResult(InternalActionContext ac, String nodeUuid, S
HibBranch branch = tx.getBranch(ac);
NodeDao nodeDao = tx.nodeDao();
HibNode node = nodeDao.loadObjectByUuid(project, ac, nodeUuid, UPDATE_PERM);
- HibNodeFieldContainer nodeFieldContainer = ctx.contentDao().findVersion(node, languageTag, branch.getUuid(), nodeVersion);
+ HibNodeFieldContainer nodeFieldContainer = ctx.contentDao().findVersion(node, languageTag[0], branch.getUuid(), nodeVersion);
if (nodeFieldContainer == null) {
throw error(BAD_REQUEST, "object_not_found_for_uuid_version", nodeUuid, nodeVersion);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java
index 2759091699..5557bda3bb 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java
@@ -16,7 +16,6 @@
import static com.gentics.mesh.example.ExampleUuids.TAG_RED_UUID;
import static com.gentics.mesh.example.ExampleUuids.UUID_1;
import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON;
-import static com.gentics.mesh.http.HttpConstants.APPLICATION_OCTET_STREAM;
import static com.gentics.mesh.http.HttpConstants.MULTIPART_FORM_DATA;
import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT;
import static io.netty.handler.codec.http.HttpResponseStatus.CREATED;
@@ -30,7 +29,9 @@
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
+import org.raml.model.ParamType;
import org.raml.model.Resource;
+import org.raml.model.parameter.QueryParameter;
import com.gentics.mesh.auth.MeshAuthChain;
import com.gentics.mesh.cli.BootstrapInitializer;
@@ -40,6 +41,7 @@
import com.gentics.mesh.core.endpoint.admin.LocalConfigApi;
import com.gentics.mesh.core.rest.navigation.NavigationResponse;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.parameter.impl.BinaryCheckParametersImpl;
import com.gentics.mesh.parameter.impl.BranchParametersImpl;
import com.gentics.mesh.parameter.impl.DeleteParametersImpl;
import com.gentics.mesh.parameter.impl.GenericParametersImpl;
@@ -176,6 +178,8 @@ private void addLanguageHandlers() {
endpoint.addUriParameter("language", "Language tag of the content which should be deleted.", "en");
endpoint.method(DELETE);
endpoint.produces(APPLICATION_JSON);
+ endpoint.addQueryParameters(DeleteParametersImpl.class);
+ endpoint.addQueryParameters(BranchParametersImpl.class);
endpoint.description("Delete the language specific content of the node.");
endpoint.exampleResponse(NO_CONTENT, "Language variation of the node has been deleted.");
endpoint.exampleResponse(NOT_FOUND, miscExamples.createMessageResponse(), "The node could not be found.");
@@ -189,11 +193,16 @@ private void addLanguageHandlers() {
}
private void addBinaryHandlers() {
+ QueryParameter publishQueryParameter = new QueryParameter();
+ publishQueryParameter.setDescription("Should the saved data be published at once");
+ publishQueryParameter.setDefaultValue("false");
+ publishQueryParameter.setType(ParamType.BOOLEAN);
+
InternalEndpointRoute fieldUpdate = createRoute();
fieldUpdate.path("/:nodeUuid/binary/:fieldName");
fieldUpdate.addUriParameter("nodeUuid", "Uuid of the node.", NODE_DELOREAN_UUID);
fieldUpdate.addUriParameter("fieldName", "Name of the field which should be created.", "stringField");
- fieldUpdate.addUriParameter("publish", "Whether the node shall be published after updating the binary field", "true");
+ fieldUpdate.addQueryParameter("publish", publishQueryParameter);
fieldUpdate.method(POST);
fieldUpdate.consumes(MULTIPART_FORM_DATA);
fieldUpdate.produces(APPLICATION_JSON);
@@ -210,10 +219,17 @@ private void addBinaryHandlers() {
binaryUploadHandler.handleUpdateField(ac, uuid, fieldName, attributes);
}, isOrderedBlockingHandlers());
+ QueryParameter lang = new QueryParameter();
+ lang.setExample("en");
+ lang.setRequired(true);
+ lang.setDescription("Node language");
InternalEndpointRoute checkCallback = createRoute();
checkCallback.path("/:nodeUuid/binary/:fieldName/checkCallback");
checkCallback.addUriParameter("nodeUuid", "Uuid of the node.", NODE_DELOREAN_UUID);
checkCallback.addUriParameter("fieldName", "Name of the field for which the check status is to be updated.", "stringField");
+ checkCallback.addQueryParameters(VersioningParametersImpl.class);
+ checkCallback.addQueryParameter("lang", lang);
+ checkCallback.addQueryParameters(BinaryCheckParametersImpl.class);
checkCallback.method(POST);
checkCallback.produces(APPLICATION_JSON);
checkCallback.exampleRequest(nodeExamples.getExampleBinaryCheckCallbackParameters());
@@ -253,6 +269,7 @@ private void addBinaryHandlers() {
fieldGet.addQueryParameters(ImageManipulationParametersImpl.class);
fieldGet.addQueryParameters(VersioningParametersImpl.class);
fieldGet.method(GET);
+ fieldGet.produces("*/*");
fieldGet.description(
"Download the binary field with the given name. You can use image query parameters for crop and resize if the binary data represents an image.");
fieldGet.blockingHandler(rc -> {
@@ -325,7 +342,7 @@ private void addS3BinaryHandlers() {
fieldUpdate.addQueryParameters(VersioningParametersImpl.class);
fieldUpdate.method(POST);
fieldUpdate.produces(APPLICATION_JSON);
- fieldUpdate.exampleRequest(nodeExamples.getExampleBinaryUploadFormParameters());
+ fieldUpdate.exampleRequest(nodeExamples.getExampleS3BinaryUploadFormParameters());
fieldUpdate.exampleResponse(OK, nodeExamples.getNodeResponseWithAllFields(), "The response contains the updated node.");
fieldUpdate.exampleResponse(NOT_FOUND, miscExamples.createMessageResponse(), "The node or the field could not be found.");
fieldUpdate.description("Create the s3 binaryfield with the given name.");
@@ -363,7 +380,7 @@ private void addS3BinaryHandlers() {
fieldMetadataExtraction.addQueryParameters(VersioningParametersImpl.class);
fieldMetadataExtraction.method(POST);
fieldMetadataExtraction.produces(APPLICATION_JSON);
- fieldMetadataExtraction.exampleRequest(nodeExamples.getExampleBinaryUploadFormParameters());
+ fieldMetadataExtraction.exampleRequest(nodeExamples.getExampleS3BinaryUploadFormParameters());
fieldMetadataExtraction.exampleResponse(OK, nodeExamples.getNodeResponseWithAllFields(), "The response contains the updated node.");
fieldMetadataExtraction.exampleResponse(NOT_FOUND, miscExamples.createMessageResponse(), "The node or the field could not be found.");
fieldMetadataExtraction.description("Parse metadata of s3 binaryfield with the given name.");
@@ -578,10 +595,9 @@ private void addUpdateHandler() {
endpoint.method(POST);
endpoint.consumes(APPLICATION_JSON);
endpoint.produces(APPLICATION_JSON);
- endpoint.exampleRequest(nodeExamples.getNodeUpdateRequest());
- endpoint.exampleResponse(OK, nodeExamples.getNodeResponse2(), "Updated node.");
+ endpoint.exampleRequest(nodeExamples.getNodeUpdateRequest2());
+ endpoint.exampleResponse(OK, nodeExamples.getNodeResponse2(), "New or updated node.");
endpoint.exampleResponse(CONFLICT, miscExamples.createMessageResponse(), "A conflict has been detected.");
- endpoint.exampleResponse(NOT_FOUND, miscExamples.createMessageResponse(), "The node could not be found.");
endpoint.events(NODE_UPDATED, NODE_CREATED, NODE_CONTENT_CREATED, NODE_UPDATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/project/LanguageEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/project/LanguageEndpoint.java
index 1fc220464f..851b67ede2 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/project/LanguageEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/project/LanguageEndpoint.java
@@ -25,6 +25,11 @@ public class LanguageEndpoint extends AbstractInternalEndpoint {
private final LanguageCrudHandler crudHandler;
+ public LanguageEndpoint() {
+ super("languages", null, null, null, null);
+ this.crudHandler = null;
+ }
+
@Inject
public LanguageEndpoint(MeshAuthChain chain, LocalConfigApi localConfigApi, Database db, MeshOptions options, LanguageCrudHandler crudHandler) {
super("languages", chain, localConfigApi, db, options);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java
index b1b1e06a11..f5fac3e1cc 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java
@@ -124,7 +124,7 @@ private void addUpdateHandler() {
endpoint.method(POST);
endpoint.consumes(APPLICATION_JSON);
endpoint.exampleRequest(roleExamples.getRoleUpdateRequest("New role name"));
- endpoint.exampleResponse(OK, roleExamples.getRoleResponse1("New role name"), "Updated role.");
+ endpoint.exampleResponse(OK, roleExamples.getRoleResponse1("New role name"), "Updated or new role.");
endpoint.events(ROLE_UPDATED, ROLE_CREATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/ProjectSchemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/ProjectSchemaEndpoint.java
index 72906b4f05..9343e5a8ea 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/ProjectSchemaEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/ProjectSchemaEndpoint.java
@@ -20,6 +20,8 @@
import com.gentics.mesh.core.db.Database;
import com.gentics.mesh.core.endpoint.admin.LocalConfigApi;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.parameter.impl.GenericParametersImpl;
+import com.gentics.mesh.parameter.impl.PagingParametersImpl;
import com.gentics.mesh.rest.InternalEndpointRoute;
import com.gentics.mesh.router.route.AbstractProjectEndpoint;
@@ -75,6 +77,8 @@ private void addReadHandlers() {
readAll.path("/");
readAll.method(GET);
readAll.description("Read multiple schemas and return a paged list response.");
+ readAll.addQueryParameters(PagingParametersImpl.class);
+ readAll.addQueryParameters(GenericParametersImpl.class);
readAll.exampleResponse(OK, schemaExamples.getSchemaListResponse(), "Loaded list of schemas.");
readAll.produces(APPLICATION_JSON);
readAll.blockingHandler(rc -> {
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java
index 0a51b7c0b9..8f0322f895 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java
@@ -137,13 +137,14 @@ private void addUpdateHandler() {
endpoint.path("/:schemaUuid");
endpoint.addUriParameter("schemaUuid", "Uuid of the schema.", SCHEMA_VEHICLE_UUID);
endpoint.method(POST);
- endpoint.description("Update the schema.");
+ endpoint.description("Update or create the schema.");
endpoint.consumes(APPLICATION_JSON);
endpoint.produces(APPLICATION_JSON);
+
endpoint.addQueryParameters(SchemaUpdateParametersImpl.class);
endpoint.exampleRequest(schemaExamples.getSchemaUpdateRequest());
- endpoint.exampleResponse(OK, schemaExamples.getSchemaResponse(), "Updated schema.");
- endpoint.events(SCHEMA_UPDATED, SCHEMA_MIGRATION_START, SCHEMA_MIGRATION_FINISHED);
+ endpoint.exampleResponse(OK, schemaExamples.getSchemaResponse(), "Updated or new schema.");
+ endpoint.events(SCHEMA_CREATED, SCHEMA_UPDATED, SCHEMA_MIGRATION_START, SCHEMA_MIGRATION_FINISHED);
endpoint.blockingHandler(rc -> {
// Update operations should always be executed sequentially - never in parallel
synchronized (schemaLock.mutex()) {
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java
index 6fc007d909..2e9b1679f7 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java
@@ -17,6 +17,7 @@
import static io.vertx.core.http.HttpMethod.DELETE;
import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.POST;
+import static io.vertx.core.http.HttpMethod.PUT;
import javax.inject.Inject;
@@ -33,6 +34,7 @@
import com.gentics.mesh.core.endpoint.tag.TagCrudHandler;
import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.parameter.impl.BranchParametersImpl;
+import com.gentics.mesh.parameter.impl.EtagParametersImpl;
import com.gentics.mesh.parameter.impl.GenericParametersImpl;
import com.gentics.mesh.parameter.impl.PagingParametersImpl;
import com.gentics.mesh.rest.InternalEndpointRoute;
@@ -102,7 +104,7 @@ private void addTagUpdateHandler() {
endpoint.produces(APPLICATION_JSON);
endpoint.description("Update the specified tag. The tag is created if no tag with the specified uuid could be found.");
endpoint.exampleRequest(tagExamples.createTagUpdateRequest("Red"));
- endpoint.exampleResponse(OK, tagExamples.createTagResponse1("Red"), "Updated tag.");
+ endpoint.exampleResponse(OK, tagExamples.createTagResponse1("Red"), "Updated or new tag.");
endpoint.events(TAG_UPDATED, TAG_CREATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
@@ -110,7 +112,6 @@ private void addTagUpdateHandler() {
String uuid = PathParameters.getTagUuid(rc);
tagCrudHandler.handleUpdate(ac, tagFamilyUuid, uuid);
}, isOrderedBlockingHandlers());
-
}
private void addTagCreateHandler() {
@@ -199,8 +200,8 @@ private void addTagRolePermissionHandler() {
InternalEndpointRoute grantPermissionsEndpoint = createRoute();
grantPermissionsEndpoint.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions");
- readPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
- readPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID);
+ grantPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
+ grantPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID);
grantPermissionsEndpoint.method(POST);
grantPermissionsEndpoint.description("Grant permissions on the tag to multiple roles.");
grantPermissionsEndpoint.consumes(APPLICATION_JSON);
@@ -215,18 +216,37 @@ private void addTagRolePermissionHandler() {
tagCrudHandler.handleGrantPermissions(ac, tagFamilyUuid, uuid);
}, isOrderedBlockingHandlers());
- InternalEndpointRoute revokePermissionsEndpoint = createRoute();
- revokePermissionsEndpoint.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions");
- readPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
- readPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID);
- revokePermissionsEndpoint.method(DELETE);
- revokePermissionsEndpoint.description("Revoke permissions on the tag from multiple roles.");
- revokePermissionsEndpoint.consumes(APPLICATION_JSON);
- revokePermissionsEndpoint.produces(APPLICATION_JSON);
- revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(false));
- revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Updated permissions.");
- revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED);
- revokePermissionsEndpoint.blockingHandler(rc -> {
+ InternalEndpointRoute revokePermissionsEndpointNonStandard = createRoute();
+ revokePermissionsEndpointNonStandard.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions");
+ revokePermissionsEndpointNonStandard.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
+ revokePermissionsEndpointNonStandard.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID);
+ revokePermissionsEndpointNonStandard.method(DELETE);
+ revokePermissionsEndpointNonStandard.description("Revoke permissions on the tag from multiple roles.");
+ revokePermissionsEndpointNonStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointNonStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(false));
+ revokePermissionsEndpointNonStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Updated permissions.");
+ revokePermissionsEndpointNonStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointNonStandard.setHidden(true);
+ revokePermissionsEndpointNonStandard.blockingHandler(rc -> {
+ InternalActionContext ac = wrap(rc);
+ String tagFamilyUuid = PathParameters.getTagFamilyUuid(rc);
+ String uuid = PathParameters.getTagUuid(rc);
+ tagCrudHandler.handleRevokePermissions(ac, tagFamilyUuid, uuid);
+ }, isOrderedBlockingHandlers());
+
+ InternalEndpointRoute revokePermissionsEndpointStandard = createRoute();
+ revokePermissionsEndpointStandard.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions");
+ revokePermissionsEndpointStandard.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
+ revokePermissionsEndpointStandard.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID);
+ revokePermissionsEndpointStandard.method(PUT);
+ revokePermissionsEndpointStandard.description("Revoke permissions on the tag from multiple roles.");
+ revokePermissionsEndpointStandard.consumes(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.produces(APPLICATION_JSON);
+ revokePermissionsEndpointStandard.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(false));
+ revokePermissionsEndpointStandard.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Updated permissions.");
+ revokePermissionsEndpointStandard.events(ROLE_PERMISSIONS_CHANGED);
+ revokePermissionsEndpointStandard.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String tagFamilyUuid = PathParameters.getTagFamilyUuid(rc);
String uuid = PathParameters.getTagUuid(rc);
@@ -274,6 +294,7 @@ private void addTagFamilyReadHandler() {
readOne.path("/:tagFamilyUuid");
readOne.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID);
readOne.method(GET);
+ readOne.addQueryParameters(EtagParametersImpl.class);
readOne.description("Read the tag family with the given uuid.");
readOne.produces(APPLICATION_JSON);
readOne.exampleResponse(OK, tagFamilyExamples.getTagFamilyResponse("Colors"), "Loaded tag family.");
@@ -321,7 +342,7 @@ private void addTagFamilyUpdateHandler() {
endpoint.consumes(APPLICATION_JSON);
endpoint.produces(APPLICATION_JSON);
endpoint.exampleRequest(tagFamilyExamples.getTagFamilyUpdateRequest("Nicer colors"));
- endpoint.exampleResponse(OK, tagFamilyExamples.getTagFamilyResponse("Nicer colors"), "Updated tag family.");
+ endpoint.exampleResponse(OK, tagFamilyExamples.getTagFamilyResponse("Nicer colors"), "Updated or new tag family.");
endpoint.events(TAG_FAMILY_UPDATED, TAG_FAMILY_CREATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java
index 583af10605..da89625972 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java
@@ -11,6 +11,7 @@
import static io.vertx.core.http.HttpMethod.DELETE;
import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.POST;
+import static io.vertx.core.http.HttpMethod.PUT;
import javax.inject.Inject;
@@ -213,8 +214,8 @@ private void addUpdateHandler() {
endpoint.produces(APPLICATION_JSON);
endpoint.addQueryParameters(UserParametersImpl.class);
endpoint.exampleRequest(userExamples.getUserUpdateRequest("jdoe42"));
- endpoint.exampleResponse(OK, userExamples.getUserResponse1("jdoe42"), "Updated user response.");
- endpoint.events(USER_UPDATED);
+ endpoint.exampleResponse(OK, userExamples.getUserResponse1("jdoe42"), "Updated or new user response.");
+ endpoint.events(USER_CREATED, USER_UPDATED);
endpoint.blockingHandler(rc -> {
InternalActionContext ac = wrap(rc);
String uuid = ac.getParameter("userUuid");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/webroot/WebRootEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/webroot/WebRootEndpoint.java
index 42bda99180..78aecd2197 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/webroot/WebRootEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/webroot/WebRootEndpoint.java
@@ -3,9 +3,10 @@
import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON;
import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT;
import static io.netty.handler.codec.http.HttpResponseStatus.CREATED;
+import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.vertx.core.http.HttpMethod.GET;
-import static io.vertx.core.http.HttpMethod.POST;
+import static io.vertx.core.http.HttpMethod.*;
import javax.inject.Inject;
@@ -77,7 +78,6 @@ private void addPathUpdateCreateHandler() {
endpoint.produces(APPLICATION_JSON);
endpoint.exampleRequest(nodeExamples.getNodeUpdateRequest());
- endpoint.exampleResponse(OK, nodeExamples.getNodeResponse2(), "Updated node.");
endpoint.exampleResponse(CREATED, nodeExamples.getNodeResponse2(), "Created node.");
endpoint.exampleResponse(CONFLICT, miscExamples.createMessageResponse(), "A conflict has been detected.");
@@ -90,6 +90,7 @@ private void addPathUpdateCreateHandler() {
private void addErrorHandlers() {
InternalEndpointRoute endpoint = createRoute();
endpoint.path("/error/404");
+ endpoint.exampleResponse(NOT_FOUND, "Web root not found");
endpoint.description("Fallback endpoint for unresolvable links which returns 404.");
endpoint.handler(rc -> {
rc.data().put("statuscode", "404");
diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/webrootfield/WebRootFieldEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/webrootfield/WebRootFieldEndpoint.java
index f233bf3f8a..f695918b47 100644
--- a/core/src/main/java/com/gentics/mesh/core/endpoint/webrootfield/WebRootFieldEndpoint.java
+++ b/core/src/main/java/com/gentics/mesh/core/endpoint/webrootfield/WebRootFieldEndpoint.java
@@ -1,5 +1,6 @@
package com.gentics.mesh.core.endpoint.webrootfield;
+import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.POST;
@@ -91,6 +92,7 @@ private void addErrorHandlers() {
InternalEndpointRoute endpoint = createRoute();
endpoint.path("/error/404");
endpoint.description("Fallback endpoint for unresolvable links which returns 404.");
+ endpoint.exampleResponse(NOT_FOUND, "Web root field not found");
endpoint.handler(rc -> {
rc.data().put("statuscode", "404");
rc.next();
diff --git a/core/src/main/java/com/gentics/mesh/dagger/module/MicrometerModule.java b/core/src/main/java/com/gentics/mesh/dagger/module/MicrometerModule.java
index d236687205..08dd7d3101 100644
--- a/core/src/main/java/com/gentics/mesh/dagger/module/MicrometerModule.java
+++ b/core/src/main/java/com/gentics/mesh/dagger/module/MicrometerModule.java
@@ -90,8 +90,6 @@ private static Optional createTag(String key, String value) {
*
* @param options
* Mesh options
- * @param meterRegistry
- * Reference to the to be used meter registry
* @return
*/
@Provides
diff --git a/core/src/main/java/com/gentics/mesh/generator/AbstractEndpointGenerator.java b/core/src/main/java/com/gentics/mesh/generator/AbstractEndpointGenerator.java
new file mode 100644
index 0000000000..ebeba53916
--- /dev/null
+++ b/core/src/main/java/com/gentics/mesh/generator/AbstractEndpointGenerator.java
@@ -0,0 +1,258 @@
+package com.gentics.mesh.generator;
+
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.FileUtils;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gentics.mesh.core.endpoint.admin.AdminEndpoint;
+import com.gentics.mesh.core.endpoint.admin.AdminEndpointImpl;
+import com.gentics.mesh.core.endpoint.admin.HealthEndpoint;
+import com.gentics.mesh.core.endpoint.admin.RestInfoEndpoint;
+import com.gentics.mesh.core.endpoint.auth.AuthenticationEndpoint;
+import com.gentics.mesh.core.endpoint.branch.BranchEndpoint;
+import com.gentics.mesh.core.endpoint.eventbus.EventbusEndpoint;
+import com.gentics.mesh.core.endpoint.group.GroupEndpoint;
+import com.gentics.mesh.core.endpoint.microschema.MicroschemaEndpoint;
+import com.gentics.mesh.core.endpoint.microschema.ProjectMicroschemaEndpoint;
+import com.gentics.mesh.core.endpoint.navroot.NavRootEndpoint;
+import com.gentics.mesh.core.endpoint.node.NodeEndpoint;
+import com.gentics.mesh.core.endpoint.project.LanguageEndpoint;
+import com.gentics.mesh.core.endpoint.project.ProjectEndpoint;
+import com.gentics.mesh.core.endpoint.project.ProjectInfoEndpoint;
+import com.gentics.mesh.core.endpoint.project.ProjectLanguageEndpoint;
+import com.gentics.mesh.core.endpoint.role.RoleEndpoint;
+import com.gentics.mesh.core.endpoint.schema.ProjectSchemaEndpoint;
+import com.gentics.mesh.core.endpoint.schema.SchemaEndpoint;
+import com.gentics.mesh.core.endpoint.tagfamily.TagFamilyEndpoint;
+import com.gentics.mesh.core.endpoint.user.UserEndpoint;
+import com.gentics.mesh.core.endpoint.utility.UtilityEndpoint;
+import com.gentics.mesh.core.endpoint.webroot.WebRootEndpoint;
+import com.gentics.mesh.core.endpoint.webrootfield.WebRootFieldEndpoint;
+import com.gentics.mesh.etc.config.Format;
+import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.etc.config.Version;
+import com.gentics.mesh.graphql.GraphQLEndpoint;
+import com.gentics.mesh.router.APIRouterImpl;
+import com.gentics.mesh.router.RootRouterImpl;
+import com.gentics.mesh.router.RouterStorageImpl;
+import com.gentics.mesh.router.route.AbstractInternalEndpoint;
+import com.gentics.mesh.search.ProjectRawSearchEndpointImpl;
+import com.gentics.mesh.search.ProjectSearchEndpointImpl;
+import com.gentics.mesh.search.RawSearchEndpointImpl;
+import com.gentics.mesh.search.SearchEndpointImpl;
+
+import io.vertx.core.Vertx;
+import io.vertx.ext.web.Router;
+
+public abstract class AbstractEndpointGenerator extends AbstractGenerator {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractEndpointGenerator.class);
+
+ public AbstractEndpointGenerator() {
+ }
+
+ public AbstractEndpointGenerator(File outputFolder, boolean cleanup) throws IOException {
+ super(outputFolder, cleanup);
+ }
+
+ public AbstractEndpointGenerator(File outputFolder) throws IOException {
+ super(outputFolder);
+ }
+
+ /**
+ * Add all project verticles to the list resources.
+ *
+ * @param consumer
+ * @throws IOException
+ * @throws Exception
+ */
+ protected void addProjectEndpoints(T consumer) throws IOException {
+ NodeEndpoint nodeEndpoint = Mockito.spy(new NodeEndpoint());
+ initEndpoint(nodeEndpoint);
+ String projectBasePath = "/{project}";
+ addEndpoints(projectBasePath, consumer, nodeEndpoint, true);
+
+ TagFamilyEndpoint tagFamilyEndpoint = Mockito.spy(new TagFamilyEndpoint());
+ initEndpoint(tagFamilyEndpoint);
+ addEndpoints(projectBasePath, consumer, tagFamilyEndpoint, true);
+
+ NavRootEndpoint navEndpoint = Mockito.spy(new NavRootEndpoint());
+ initEndpoint(navEndpoint);
+ addEndpoints(projectBasePath, consumer, navEndpoint, true);
+
+ WebRootEndpoint webEndpoint = Mockito.spy(new WebRootEndpoint());
+ initEndpoint(webEndpoint);
+ addEndpoints(projectBasePath, consumer, webEndpoint, true);
+
+ WebRootFieldEndpoint webFieldEndpoint = Mockito.spy(new WebRootFieldEndpoint());
+ initEndpoint(webFieldEndpoint);
+ addEndpoints(projectBasePath, consumer, webFieldEndpoint, true);
+
+ BranchEndpoint branchEndpoint = Mockito.spy(new BranchEndpoint());
+ initEndpoint(branchEndpoint);
+ addEndpoints(projectBasePath, consumer, branchEndpoint, true);
+
+ GraphQLEndpoint graphqlEndpoint = Mockito.spy(new GraphQLEndpoint());
+ initEndpoint(graphqlEndpoint);
+ addEndpoints(projectBasePath, consumer, graphqlEndpoint, true);
+
+ ProjectSearchEndpointImpl projectSearchEndpoint = Mockito.spy(new ProjectSearchEndpointImpl());
+ initEndpoint(projectSearchEndpoint);
+ addEndpoints(projectBasePath, consumer, projectSearchEndpoint, true);
+
+ ProjectRawSearchEndpointImpl projectRawSearchEndpoint = Mockito.spy(new ProjectRawSearchEndpointImpl());
+ initEndpoint(projectRawSearchEndpoint);
+ addEndpoints(projectBasePath, consumer, projectRawSearchEndpoint, true);
+
+ ProjectSchemaEndpoint projectSchemaEndpoint = Mockito.spy(new ProjectSchemaEndpoint());
+ initEndpoint(projectSchemaEndpoint);
+ addEndpoints(projectBasePath, consumer, projectSchemaEndpoint, true);
+
+ ProjectMicroschemaEndpoint projectMicroschemaEndpoint = Mockito.spy(new ProjectMicroschemaEndpoint());
+ initEndpoint(projectMicroschemaEndpoint);
+ addEndpoints(projectBasePath, consumer, projectMicroschemaEndpoint, true);
+
+ ProjectLanguageEndpoint projectLanguageEndpoint = Mockito.spy(new ProjectLanguageEndpoint());
+ initEndpoint(projectLanguageEndpoint);
+ addEndpoints(projectBasePath, consumer, projectLanguageEndpoint, true);
+ }
+
+ /**
+ * Add all core verticles to the map of RAML resources.
+ *
+ * @param consumer
+ * @throws IOException
+ * @throws Exception
+ */
+ protected void addCoreEndpoints(T consumer) throws IOException {
+ String coreBasePath = "";
+ UserEndpoint userEndpoint = Mockito.spy(new UserEndpoint());
+ initEndpoint(userEndpoint);
+ addEndpoints(coreBasePath, consumer, userEndpoint, false);
+
+ RoleEndpoint roleEndpoint = Mockito.spy(new RoleEndpoint());
+ initEndpoint(roleEndpoint);
+ addEndpoints(coreBasePath, consumer, roleEndpoint, false);
+
+ GroupEndpoint groupEndpoint = Mockito.spy(new GroupEndpoint());
+ initEndpoint(groupEndpoint);
+ addEndpoints(coreBasePath, consumer, groupEndpoint, false);
+
+ ProjectEndpoint projectEndpoint = Mockito.spy(new ProjectEndpoint());
+ initEndpoint(projectEndpoint);
+ addEndpoints(coreBasePath, consumer, projectEndpoint, false);
+
+ SchemaEndpoint schemaEndpoint = Mockito.spy(new SchemaEndpoint());
+ initEndpoint(schemaEndpoint);
+ addEndpoints(coreBasePath, consumer, schemaEndpoint, false);
+
+ MicroschemaEndpoint microschemaEndpoint = Mockito.spy(new MicroschemaEndpoint());
+ initEndpoint(microschemaEndpoint);
+ addEndpoints(coreBasePath, consumer, microschemaEndpoint, false);
+
+ AdminEndpoint adminEndpoint = Mockito.spy(new AdminEndpointImpl());
+ initEndpoint(adminEndpoint);
+ addEndpoints(coreBasePath, consumer, adminEndpoint, false);
+
+ HealthEndpoint healthEndpoint = Mockito.spy(new HealthEndpoint());
+ initEndpoint(healthEndpoint);
+ addEndpoints(coreBasePath, consumer, healthEndpoint, false);
+
+ SearchEndpointImpl searchEndpoint = Mockito.spy(new SearchEndpointImpl());
+ initEndpoint(searchEndpoint);
+ addEndpoints(coreBasePath, consumer, searchEndpoint, false);
+
+ RawSearchEndpointImpl rawSearchEndpoint = Mockito.spy(new RawSearchEndpointImpl());
+ initEndpoint(rawSearchEndpoint);
+ addEndpoints(coreBasePath, consumer, rawSearchEndpoint, false);
+
+ UtilityEndpoint utilityEndpoint = Mockito.spy(new UtilityEndpoint());
+ initEndpoint(utilityEndpoint);
+ addEndpoints(coreBasePath, consumer, utilityEndpoint, false);
+
+ AuthenticationEndpoint authEndpoint = Mockito.spy(new AuthenticationEndpoint());
+ initEndpoint(authEndpoint);
+ addEndpoints(coreBasePath, consumer, authEndpoint, false);
+
+ EventbusEndpoint eventbusEndpoint = Mockito.spy(new EventbusEndpoint());
+ initEndpoint(eventbusEndpoint);
+ addEndpoints(coreBasePath, consumer, eventbusEndpoint, false);
+
+ RouterStorageImpl rs = Mockito.mock(RouterStorageImpl.class);
+ RootRouterImpl rootRouter = Mockito.mock(RootRouterImpl.class);
+ Mockito.when(rs.root()).thenReturn(rootRouter);
+ APIRouterImpl apiRouter = Mockito.mock(APIRouterImpl.class);
+ Mockito.when(rootRouter.apiRouter()).thenReturn(apiRouter);
+ RestInfoEndpoint infoEndpoint = Mockito.spy(new RestInfoEndpoint(""));
+ infoEndpoint.init(null, rs);
+ initEndpoint(infoEndpoint);
+ addEndpoints(coreBasePath, consumer, infoEndpoint, false);
+
+ ProjectInfoEndpoint projectInfoEndpoint = Mockito.spy(new ProjectInfoEndpoint());
+ initEndpoint(projectInfoEndpoint);
+ addEndpoints(coreBasePath, consumer, projectInfoEndpoint, false);
+
+ LanguageEndpoint languageEndpoint = Mockito.spy(new LanguageEndpoint());
+ initEndpoint(languageEndpoint);
+ addEndpoints(coreBasePath, consumer, languageEndpoint, false);
+ }
+
+ /**
+ * Add any extra verticles to the consumer.
+ *
+ * @param resources
+ * @throws IOException
+ */
+ protected void addExtraEndpoints(T consumer) throws IOException {
+ }
+
+ /**
+ * Add an endpoint to the data consumer.
+ *
+ * @param coreBasePath
+ * @param consumer
+ * @param projectInfoEndpoint
+ * @param isProject
+ * @throws IOException
+ */
+ protected abstract void addEndpoints(String coreBasePath, T consumer, AbstractInternalEndpoint projectInfoEndpoint, boolean isProject) throws IOException;
+
+ /**
+ * Mock an endpoint with data, full enough for the generator to succeed.
+ *
+ * @param endpoint
+ */
+ protected void initEndpoint(AbstractInternalEndpoint endpoint) {
+ Vertx vertx = mock(Vertx.class);
+ MeshOptions options = mock(MeshOptions.class);
+ Mockito.when(endpoint.getRouter()).thenReturn(Router.router(vertx));
+ Mockito.when(endpoint.getOptions()).thenReturn(options);
+ Mockito.when(options.getDefaultOpenAPIFormat()).thenReturn(Format.YAML);
+ Mockito.when(options.getDefaultOpenAPIVersion()).thenReturn(Version.V30);
+ endpoint.registerEndPoints();
+ }
+
+ /**
+ * Save the string content to the given file in the output folder.
+ *
+ * @param filename
+ * Name of the file to be written to
+ * @param content
+ * Content to be written
+ * @throws IOException
+ */
+ public void writeFile(String filename, String content) throws IOException {
+ if (outputFolder != null) {
+ File outputFile = new File(outputFolder, filename);
+ FileUtils.writeStringToFile(outputFile, content, StandardCharsets.UTF_8);
+ log.info("File saved to {" + outputFile.getPath() + "}");
+ }
+ }
+}
diff --git a/core/src/main/java/com/gentics/mesh/generator/OpenAPIMockAPIGenerator.java b/core/src/main/java/com/gentics/mesh/generator/OpenAPIMockAPIGenerator.java
new file mode 100644
index 0000000000..aeba46c75b
--- /dev/null
+++ b/core/src/main/java/com/gentics/mesh/generator/OpenAPIMockAPIGenerator.java
@@ -0,0 +1,84 @@
+package com.gentics.mesh.generator;
+
+import static com.gentics.mesh.MeshVersion.CURRENT_API_VERSION;
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gentics.mesh.MeshVersion;
+import com.gentics.mesh.router.route.AbstractInternalEndpoint;
+import com.gentics.mesh.util.MeshOpenAPIv3Generator;
+import com.gentics.vertx.openapi.OpenAPIv3Generator;
+import com.gentics.vertx.openapi.model.Format;
+import com.gentics.vertx.openapi.model.OpenAPIGenerationException;
+
+import io.vertx.ext.web.Router;
+
+/**
+ * OpenAPI v3 API definition generator. Outputs JSON and YAML schemas.
+ *
+ * @author plyhun
+ *
+ */
+public class OpenAPIMockAPIGenerator extends AbstractEndpointGenerator {
+
+ private static final Logger log = LoggerFactory.getLogger(OpenAPIMockAPIGenerator.class);
+
+ private final MeshOpenAPIv3Generator generator;
+ private final Map routers = new HashMap<>();
+ private final String fileName;
+
+ public OpenAPIMockAPIGenerator() {
+ super();
+ this.fileName = null;
+ this.generator = new MeshOpenAPIv3Generator(MeshVersion.getPlainVersion(), Collections.emptyList(), Optional.empty(), Optional.empty());
+ }
+
+ public OpenAPIMockAPIGenerator(File outputFolder, String fileName, boolean cleanup) throws IOException {
+ super(new File(outputFolder, "api"), cleanup);
+ this.fileName = fileName;
+ this.generator = new MeshOpenAPIv3Generator(MeshVersion.getPlainVersion(), Collections.emptyList(), Optional.empty(), Optional.empty());
+ }
+
+ public OpenAPIMockAPIGenerator(File outputFolder, String fileName) throws IOException {
+ this(outputFolder, fileName, false);
+ }
+
+ public String generate(String format) throws IOException, OpenAPIGenerationException {
+ log.info("Starting OpenAPIv3 generation...");
+ addCoreEndpoints(generator);
+ addProjectEndpoints(generator);
+ addExtraEndpoints(generator);
+
+ return generator.generate(routers, Format.parse(format), true, false);
+ }
+
+ @Override
+ protected void addEndpoints(String basePath, OpenAPIv3Generator consumer, AbstractInternalEndpoint verticle,
+ boolean isProject) throws IOException {
+ String fullPath = "/api/v" + CURRENT_API_VERSION + basePath + "/" + verticle.getBasePath();
+ if (isEmpty(verticle.getBasePath())) {
+ fullPath = "/api/v" + CURRENT_API_VERSION + basePath;
+ }
+ routers.put(verticle.getRouter(), fullPath);
+ }
+
+ /**
+ * Start the generator.
+ *
+ * @throws IOException
+ * @throws OpenAPIGenerationException
+ */
+ public void run() throws IOException, OpenAPIGenerationException {
+ String yaml = generate("yaml");
+ writeFile(fileName, yaml);
+ }
+}
diff --git a/core/src/main/java/com/gentics/mesh/generator/RAMLGenerator.java b/core/src/main/java/com/gentics/mesh/generator/RAMLGenerator.java
index 6fd6067964..ccdfdc2e9a 100644
--- a/core/src/main/java/com/gentics/mesh/generator/RAMLGenerator.java
+++ b/core/src/main/java/com/gentics/mesh/generator/RAMLGenerator.java
@@ -2,7 +2,6 @@
import static com.gentics.mesh.MeshVersion.CURRENT_API_VERSION;
import static org.apache.commons.lang3.StringUtils.isEmpty;
-import static org.mockito.Mockito.mock;
import java.io.File;
import java.io.IOException;
@@ -12,8 +11,6 @@
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
-import org.apache.commons.io.FileUtils;
-import org.mockito.Mockito;
import org.raml.emitter.RamlEmitter;
import org.raml.model.Action;
import org.raml.model.ActionType;
@@ -26,47 +23,15 @@
import org.slf4j.LoggerFactory;
import com.gentics.mesh.MeshVersion;
-import com.gentics.mesh.core.endpoint.admin.AdminEndpoint;
-import com.gentics.mesh.core.endpoint.admin.AdminEndpointImpl;
-import com.gentics.mesh.core.endpoint.admin.HealthEndpoint;
-import com.gentics.mesh.core.endpoint.admin.RestInfoEndpoint;
-import com.gentics.mesh.core.endpoint.auth.AuthenticationEndpoint;
-import com.gentics.mesh.core.endpoint.branch.BranchEndpoint;
-import com.gentics.mesh.core.endpoint.eventbus.EventbusEndpoint;
-import com.gentics.mesh.core.endpoint.group.GroupEndpoint;
-import com.gentics.mesh.core.endpoint.microschema.MicroschemaEndpoint;
-import com.gentics.mesh.core.endpoint.microschema.ProjectMicroschemaEndpoint;
-import com.gentics.mesh.core.endpoint.navroot.NavRootEndpoint;
-import com.gentics.mesh.core.endpoint.node.NodeEndpoint;
-import com.gentics.mesh.core.endpoint.project.ProjectEndpoint;
-import com.gentics.mesh.core.endpoint.project.ProjectInfoEndpoint;
-import com.gentics.mesh.core.endpoint.role.RoleEndpoint;
-import com.gentics.mesh.core.endpoint.schema.ProjectSchemaEndpoint;
-import com.gentics.mesh.core.endpoint.schema.SchemaEndpoint;
-import com.gentics.mesh.core.endpoint.tagfamily.TagFamilyEndpoint;
-import com.gentics.mesh.core.endpoint.user.UserEndpoint;
-import com.gentics.mesh.core.endpoint.utility.UtilityEndpoint;
-import com.gentics.mesh.core.endpoint.webroot.WebRootEndpoint;
-import com.gentics.mesh.core.endpoint.webrootfield.WebRootFieldEndpoint;
-import com.gentics.mesh.graphql.GraphQLEndpoint;
import com.gentics.mesh.rest.InternalEndpointRoute;
-import com.gentics.mesh.router.APIRouterImpl;
-import com.gentics.mesh.router.RootRouterImpl;
-import com.gentics.mesh.router.RouterStorageImpl;
import com.gentics.mesh.router.route.AbstractInternalEndpoint;
-import com.gentics.mesh.search.ProjectRawSearchEndpointImpl;
-import com.gentics.mesh.search.ProjectSearchEndpointImpl;
-import com.gentics.mesh.search.RawSearchEndpointImpl;
-import com.gentics.mesh.search.SearchEndpointImpl;
-import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
-import io.vertx.ext.web.Router;
/**
* Generator for RAML documentation. The generation mocks all endpoint classes and extracts the routes from these endpoints in order to generate the RAML.
*/
-public class RAMLGenerator extends AbstractGenerator {
+public class RAMLGenerator extends AbstractEndpointGenerator
+
+ com.gentics
+ vertx-openapi
+
+
+ org.slf4j
+ slf4j-parent
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ org.slf4j
+ slf4j-api
+
+
+ commons-validator
+ commons-validator
+
+
+ com.github.fge
+ json-schema-validator
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+
+
+
diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/JobDao.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/JobDao.java
index d0a2b0417d..c39d30f08e 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/JobDao.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/JobDao.java
@@ -103,7 +103,6 @@ default Page extends HibJob> findAllNoPerm(InternalActionContext ac, PagingPar
* Delete the job.
*
* @param job
- * @param bac
*/
void delete(HibJob job);
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/AbstractParameters.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/AbstractParameters.java
index 4a18a516e4..e040590f9c 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/AbstractParameters.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/AbstractParameters.java
@@ -1,19 +1,20 @@
package com.gentics.mesh.parameter;
+import java.util.Map;
+
+import org.raml.model.parameter.QueryParameter;
+
import com.gentics.mesh.doc.GenerateDocumentation;
import com.gentics.mesh.handler.ActionContext;
+import com.gentics.vertx.openapi.model.parameters.SimpleParameterProviderImpl;
import io.vertx.core.MultiMap;
-import java.util.Map;
-
-import static com.gentics.mesh.util.HttpQueryUtils.toMap;
-
/**
* Abstract class for parameter provider implementations.
*/
@GenerateDocumentation
-public abstract class AbstractParameters implements ParameterProvider {
+public abstract class AbstractParameters extends SimpleParameterProviderImpl {
protected MultiMap parameters;
@@ -23,38 +24,25 @@ public AbstractParameters(ActionContext ac) {
}
public AbstractParameters(MultiMap parameters) {
- this.parameters = parameters;
+ super(parameters);
}
public AbstractParameters() {
this(MultiMap.caseInsensitiveMultiMap());
}
+ /**
+ * Return the RAML parameters for this provider.
+ *
+ * @return
+ */
+ @Override
+ public abstract Map extends String, ? extends QueryParameter> getRAMLParameters();
+
/**
* Returns the human readable name of the parameters.
*
* @return
*/
public abstract String getName();
-
- @Override
- public String getParameter(String name) {
- return parameters.get(name);
- }
-
- @Override
- public Map getParameters() {
- return toMap(parameters);
- }
-
- @Override
- public void setParameter(String name, String value) {
- parameters.set(name, value);
- }
-
- @Override
- public String toString() {
- return getQueryParameters();
- }
-
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/ParameterProviderContext.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/ParameterProviderContext.java
index dea6134b71..8d3eb22159 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/ParameterProviderContext.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/ParameterProviderContext.java
@@ -2,15 +2,18 @@
import com.gentics.mesh.handler.ActionContext;
import com.gentics.mesh.parameter.impl.BackupParametersImpl;
+import com.gentics.mesh.parameter.impl.BinaryCheckParametersImpl;
import com.gentics.mesh.parameter.impl.BranchParametersImpl;
import com.gentics.mesh.parameter.impl.ConsistencyCheckParametersImpl;
import com.gentics.mesh.parameter.impl.DeleteParametersImpl;
import com.gentics.mesh.parameter.impl.DisplayParametersImpl;
+import com.gentics.mesh.parameter.impl.EtagParametersImpl;
import com.gentics.mesh.parameter.impl.GenericParametersImpl;
import com.gentics.mesh.parameter.impl.ImageManipulationParametersImpl;
import com.gentics.mesh.parameter.impl.ImageManipulationRetrievalParametersImpl;
import com.gentics.mesh.parameter.impl.IndexMaintenanceParametersImpl;
import com.gentics.mesh.parameter.impl.JobParametersImpl;
+import com.gentics.mesh.parameter.impl.LanguageParametersImpl;
import com.gentics.mesh.parameter.impl.NodeParametersImpl;
import com.gentics.mesh.parameter.impl.PagingParametersImpl;
import com.gentics.mesh.parameter.impl.ProjectLoadParametersImpl;
@@ -44,6 +47,10 @@ default VersioningParameters getVersioningParameters() {
return new VersioningParametersImpl(this);
}
+ default LanguageParameters getLanguageParameters() {
+ return new LanguageParametersImpl(this);
+ }
+
default PagingParameters getPagingParameters() {
return new PagingParametersImpl(this);
}
@@ -80,6 +87,10 @@ default GenericParameters getGenericParameters() {
return new GenericParametersImpl(this);
}
+ default EtagParameters getEtagParameters() {
+ return new EtagParametersImpl(this);
+ }
+
default ImageManipulationRetrievalParameters getImageManipulationRetrievalParameters() {
return new ImageManipulationRetrievalParametersImpl(this);
}
@@ -111,4 +122,8 @@ default DisplayParameters getDisplayParameters() {
default ConsistencyCheckParameters getConsistencyCheckParameters() {
return new ConsistencyCheckParametersImpl(this);
}
+
+ default BinaryCheckParameters getBinaryCheckParameters() {
+ return new BinaryCheckParametersImpl(this);
+ }
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/BinaryCheckParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/BinaryCheckParametersImpl.java
new file mode 100644
index 0000000000..eaf18e9657
--- /dev/null
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/BinaryCheckParametersImpl.java
@@ -0,0 +1,46 @@
+package com.gentics.mesh.parameter.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.raml.model.ParamType;
+import org.raml.model.parameter.QueryParameter;
+
+import com.gentics.mesh.handler.ActionContext;
+import com.gentics.mesh.parameter.AbstractParameters;
+import com.gentics.mesh.parameter.BinaryCheckParameters;
+
+public class BinaryCheckParametersImpl extends AbstractParameters implements BinaryCheckParameters {
+
+ public BinaryCheckParametersImpl(ActionContext ac) {
+ super(ac);
+ }
+
+ public BinaryCheckParametersImpl() {
+ super();
+ }
+
+ @Override
+ public void validate() {
+
+ }
+
+ @Override
+ public Map extends String, ? extends QueryParameter> getRAMLParameters() {
+ Map parameters = new HashMap<>();
+
+ QueryParameter langParameter = new QueryParameter();
+ langParameter.setDescription(".");
+ langParameter.setExample("lhdgfsgfvaoyegfy");
+ langParameter.setRequired(true);
+ langParameter.setType(ParamType.STRING);
+ parameters.put(SECRET_PARAMETER_KEY, langParameter);
+
+ return parameters;
+ }
+
+ @Override
+ public String getName() {
+ return "Binary check parameters";
+ }
+}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/EtagParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/EtagParametersImpl.java
new file mode 100644
index 0000000000..c84c4552b8
--- /dev/null
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/EtagParametersImpl.java
@@ -0,0 +1,43 @@
+package com.gentics.mesh.parameter.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.raml.model.ParamType;
+import org.raml.model.parameter.QueryParameter;
+
+import com.gentics.mesh.handler.ActionContext;
+import com.gentics.mesh.parameter.AbstractParameters;
+import com.gentics.mesh.parameter.EtagParameters;
+
+/**
+ * @see EtagParameters
+ */
+public class EtagParametersImpl extends AbstractParameters implements EtagParameters {
+
+ public EtagParametersImpl(ActionContext ac) {
+ super(ac);
+ }
+
+ public EtagParametersImpl() {
+ }
+
+ @Override
+ public String getName() {
+ return "ETAG REST query parameters";
+ }
+
+ @Override
+ public Map extends String, ? extends QueryParameter> getRAMLParameters() {
+ Map parameters = new HashMap<>();
+
+ QueryParameter etagParam = new QueryParameter();
+ etagParam.setDescription(
+ "Parameter which can be used to disable the etag parameter generation and thus increase performance when etags are not needed.");
+ etagParam.setType(ParamType.BOOLEAN);
+ etagParam.setDefaultValue("true");
+ parameters.put(ETAG_PARAM_KEY, etagParam);
+
+ return parameters;
+ }
+}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/GenericParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/GenericParametersImpl.java
index 14dd643be6..80bf255abb 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/GenericParametersImpl.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/GenericParametersImpl.java
@@ -7,13 +7,12 @@
import org.raml.model.parameter.QueryParameter;
import com.gentics.mesh.handler.ActionContext;
-import com.gentics.mesh.parameter.AbstractParameters;
import com.gentics.mesh.parameter.GenericParameters;
/**
* @see GenericParameters
*/
-public class GenericParametersImpl extends AbstractParameters implements GenericParameters {
+public class GenericParametersImpl extends EtagParametersImpl implements GenericParameters {
public GenericParametersImpl(ActionContext ac) {
super(ac);
@@ -35,21 +34,15 @@ public String getName() {
@Override
public Map extends String, ? extends QueryParameter> getRAMLParameters() {
- Map parameters = new HashMap<>();
+ Map parameters = new HashMap<>(super.getRAMLParameters());
QueryParameter fieldsParam = new QueryParameter();
fieldsParam.setDescription("Limit the output to certain fields. This is useful in order to reduce the response JSON overhead.");
fieldsParam.setType(ParamType.STRING);
fieldsParam.setDefaultValue("");
+ fieldsParam.setExample("uuid,name");
parameters.put(FIELDS_PARAM_KEY, fieldsParam);
- QueryParameter etagParam = new QueryParameter();
- etagParam.setDescription(
- "Parameter which can be used to disable the etag parameter generation and thus increase performance when etags are not needed.");
- etagParam.setType(ParamType.BOOLEAN);
- etagParam.setDefaultValue("true");
- parameters.put(ETAG_PARAM_KEY, etagParam);
-
return parameters;
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/JobParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/JobParametersImpl.java
index fb9e361bf5..e90b0bccaf 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/JobParametersImpl.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/JobParametersImpl.java
@@ -1,11 +1,15 @@
package com.gentics.mesh.parameter.impl;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import org.apache.commons.lang3.ArrayUtils;
import org.raml.model.ParamType;
import org.raml.model.parameter.QueryParameter;
+import com.gentics.mesh.core.rest.job.JobStatus;
+import com.gentics.mesh.core.rest.job.JobType;
import com.gentics.mesh.handler.ActionContext;
import com.gentics.mesh.parameter.AbstractParameters;
import com.gentics.mesh.parameter.JobParameters;
@@ -34,9 +38,9 @@ public JobParametersImpl(ActionContext ac) {
Map parameters = new HashMap<>();
parameters.put(STATUS_PARAMETER_KEY, createQueryParameter(
- "Parameter for filtering jobs by their status. Multiple values can be given separated by commas."));
+ "Parameter for filtering jobs by their status. Multiple values can be given separated by commas.", ArrayUtils.toStringArray(JobStatus.values())));
parameters.put(TYPE_PARAMETER_KEY, createQueryParameter(
- "Parameter for filtering jobs by their type. Multiple values can be given separated by commas."));
+ "Parameter for filtering jobs by their type. Multiple values can be given separated by commas.", ArrayUtils.toStringArray(JobType.values())));
parameters.put(BRANCH_NAME_PARAMETER_KEY, createQueryParameter(
"Parameter for filtering jobs by the branch name. Multiple values can be given separated by commas."));
parameters.put(BRANCH_UUID_PARAMETER_KEY, createQueryParameter(
@@ -67,11 +71,15 @@ public String getName() {
* @param description parameter description
* @return query parameter
*/
- protected QueryParameter createQueryParameter(String description) {
+ protected QueryParameter createQueryParameter(String description, String... enumValues) {
QueryParameter param = new QueryParameter();
param.setDescription(description);
param.setType(ParamType.STRING);
- param.setDefaultValue("");
+ if (enumValues.length > 0) {
+ param.setEnumeration(Arrays.asList(enumValues));
+ } else {
+ param.setDefaultValue("");
+ }
return param;
}
}
\ No newline at end of file
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/LanguageParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/LanguageParametersImpl.java
new file mode 100644
index 0000000000..a76b703526
--- /dev/null
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/LanguageParametersImpl.java
@@ -0,0 +1,42 @@
+package com.gentics.mesh.parameter.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.raml.model.ParamType;
+import org.raml.model.parameter.QueryParameter;
+
+import com.gentics.mesh.handler.ActionContext;
+import com.gentics.mesh.parameter.AbstractParameters;
+
+public class LanguageParametersImpl extends AbstractParameters implements com.gentics.mesh.parameter.LanguageParameters {
+
+ public LanguageParametersImpl(ActionContext ac) {
+ super(ac);
+ }
+
+ public LanguageParametersImpl() {
+ super();
+ }
+
+ @Override
+ public Map extends String, ? extends QueryParameter> getRAMLParameters() {
+ Map parameters = new HashMap<>();
+
+ // lang
+ QueryParameter langParameter = new QueryParameter();
+ langParameter.setDescription(
+ "ISO 639-1 language tag of the language which should be loaded. Fallback handling can be applied by specifying multiple languages in a comma-separated list. The first matching language will be returned. If omitted or the requested language is not available then the _defaultLanguage_ as configured in _mesh.yml_ will be returned.");
+ langParameter.setExample("en,de");
+ langParameter.setRequired(false);
+ langParameter.setType(ParamType.STRING);
+ parameters.put(LANGUAGES_QUERY_PARAM_KEY, langParameter);
+
+ return parameters;
+ }
+
+ @Override
+ public String getName() {
+ return "Language parameters";
+ }
+}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/NodeParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/NodeParametersImpl.java
index 990d508c8b..d4609333d2 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/NodeParametersImpl.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/NodeParametersImpl.java
@@ -1,19 +1,21 @@
package com.gentics.mesh.parameter.impl;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Collectors;
import org.raml.model.ParamType;
import org.raml.model.parameter.QueryParameter;
import com.gentics.mesh.handler.ActionContext;
-import com.gentics.mesh.parameter.AbstractParameters;
+import com.gentics.mesh.parameter.LinkType;
import com.gentics.mesh.parameter.NodeParameters;
/**
* @see NodeParameters
*/
-public class NodeParametersImpl extends AbstractParameters implements NodeParameters {
+public class NodeParametersImpl extends LanguageParametersImpl implements NodeParameters {
public NodeParametersImpl(ActionContext ac) {
super(ac);
@@ -35,16 +37,7 @@ public String getName() {
@Override
public Map extends String, ? extends QueryParameter> getRAMLParameters() {
- Map parameters = new HashMap<>();
-
- // lang
- QueryParameter langParameter = new QueryParameter();
- langParameter.setDescription(
- "ISO 639-1 language tag of the language which should be loaded. Fallback handling can be applied by specifying multiple languages in a comma-separated list. The first matching language will be returned. If omitted or the requested language is not available then the _defaultLanguage_ as configured in _mesh.yml_ will be returned.");
- langParameter.setExample("en,de");
- langParameter.setRequired(false);
- langParameter.setType(ParamType.STRING);
- parameters.put(LANGUAGES_QUERY_PARAM_KEY, langParameter);
+ Map parameters = new HashMap<>(super.getRAMLParameters());
// resolveLinks
QueryParameter resolveLinksParameter = new QueryParameter();
@@ -53,6 +46,7 @@ public String getName() {
resolveLinksParameter.setExample("medium");
resolveLinksParameter.setRequired(false);
resolveLinksParameter.setType(ParamType.STRING);
+ resolveLinksParameter.setEnumeration(Arrays.asList(LinkType.values()).stream().map(e -> e.name().toLowerCase()).collect(Collectors.toList()));
parameters.put(RESOLVE_LINKS_QUERY_PARAM_KEY, resolveLinksParameter);
return parameters;
diff --git a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/SortingParametersImpl.java b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/SortingParametersImpl.java
index 17805f4b71..7e85bae2d6 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/SortingParametersImpl.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/parameter/impl/SortingParametersImpl.java
@@ -3,6 +3,7 @@
import static com.gentics.mesh.core.rest.error.Errors.error;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -56,11 +57,11 @@ public SortingParametersImpl(ActionContext ac) {
// sort order
QueryParameter sortOrderParameter = new QueryParameter();
- sortOrderParameter.setDescription("Field order (ASC/DESC/UNSORTED) to sort the result by.");
- sortOrderParameter.setDefaultValue(SortingParameters.DEFAULT_SORT_ORDER.name());
+ sortOrderParameter.setDescription("Field order (ASC/DESC) to sort the result by.");
sortOrderParameter.setExample(SortOrder.ASCENDING.name());
sortOrderParameter.setRequired(false);
sortOrderParameter.setType(ParamType.STRING);
+ sortOrderParameter.setEnumeration(Arrays.asList(SortOrder.values()).stream().filter(e -> SortOrder.UNSORTED != e).map(e -> e.getValue().toLowerCase()).collect(Collectors.toList()));
parameters.put(SortingParameters.SORT_ORDER_PARAMETER_KEY, sortOrderParameter);
return parameters;
diff --git a/mdm/api/src/main/java/com/gentics/mesh/rest/InternalEndpointRoute.java b/mdm/api/src/main/java/com/gentics/mesh/rest/InternalEndpointRoute.java
index 83a476a641..3cdd4a3607 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/rest/InternalEndpointRoute.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/rest/InternalEndpointRoute.java
@@ -1,404 +1,14 @@
package com.gentics.mesh.rest;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import io.vertx.ext.web.Router;
-import org.codehaus.jettison.json.JSONObject;
-import org.raml.model.MimeType;
-import org.raml.model.Response;
-import org.raml.model.parameter.FormParameter;
-import org.raml.model.parameter.QueryParameter;
-import org.raml.model.parameter.UriParameter;
-
import com.gentics.mesh.core.rest.MeshEvent;
-import com.gentics.mesh.core.rest.admin.localconfig.LocalConfigModel;
-import com.gentics.mesh.core.rest.common.RestModel;
-import com.gentics.mesh.parameter.ParameterProvider;
-import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Handler;
-import io.vertx.core.http.HttpMethod;
-import io.vertx.ext.web.Route;
import io.vertx.ext.web.RoutingContext;
/**
* Simple wrapper for vert.x routes. The wrapper is commonly used to generate RAML descriptions for the route.
*/
-public interface InternalEndpointRoute extends Comparable {
-
- /**
- * Wrapper for {@link Route#path(String)}.
- *
- * @param path
- * @return Fluent API
- */
- InternalEndpointRoute path(String path);
-
- /**
- * Set the http method of the endpoint.
- *
- * @param method
- * @return Fluent API
- */
- InternalEndpointRoute method(HttpMethod method);
-
- /**
- * Add a content type consumed by this endpoint. Used for content based routing.
- *
- * @param contentType
- * the content type
- * @return Fluent API
- */
- InternalEndpointRoute consumes(String contentType);
-
- /**
- * Set the request handler for the endpoint.
- *
- * @param requestHandler
- * @return Fluent API
- */
- InternalEndpointRoute handler(Handler requestHandler);
-
- /**
- * Create a sub router
- * @param router
- * @return
- */
- InternalEndpointRoute subRouter(Router router);
-
- /**
- * Wrapper for {@link Route#last()}
- *
- * @return Fluent API
- */
- InternalEndpointRoute last();
-
- /**
- * Wrapper for {@link Route#order(int)}
- *
- * @param order
- * @return Fluent API
- */
- InternalEndpointRoute order(int order);
-
- /**
- * Validate that all mandatory fields have been set.
- *
- * @return Fluent API
- */
- InternalEndpointRoute validate();
-
- /**
- * Wrapper for {@link Route#remove()}
- *
- * @return Fluent API
- */
- InternalEndpointRoute remove();
-
- /**
- * Wrapper for {@link Route#disable()}
- *
- * @return Fluent API
- */
- InternalEndpointRoute disable();
-
- /**
- * Wrapper for {@link Route#enable()}
- *
- * @return Fluent API
- */
- InternalEndpointRoute enable();
-
- /**
- * Wrapper for {@link Route#useNormalisedPath(boolean)}.
- *
- * @param useNormalisedPath
- * @return
- */
- InternalEndpointRoute useNormalisedPath(boolean useNormalisedPath);
-
- /**
- * Wrapper for {@link Route#getPath()}
- *
- * @return the path prefix (if any) for this route
- */
- String getPath();
-
- /**
- * Return the endpoint description.
- *
- * @return Endpoint description
- */
- String getDescription();
-
- /**
- * Return the display name for the endpoint.
- *
- * @return Endpoint display name
- */
- String getDisplayName();
-
- /**
- * Add the given response to the example responses.
- *
- * @param status
- * Status code of the response
- * @param description
- * Description of the response
- * @return Fluent API
- */
- InternalEndpointRoute exampleResponse(HttpResponseStatus status, String description);
-
- /**
- * Add the given response to the example responses.
- *
- * @param status
- * Status code for the example response
- * @param model
- * Model which will be turned into JSON
- * @param description
- * Description of the example response
- * @return Fluent API
- */
- InternalEndpointRoute exampleResponse(HttpResponseStatus status, Object model, String description);
-
- /**
- * Add the given response to the example responses.
- *
- * @param status
- * Status code of the example response
- * @param description
- * Description of the example
- * @param headerName
- * Name of the header value
- * @param example
- * Example header value
- * @param headerDescription
- * Description of the header
- * @return
- */
- InternalEndpointRoute exampleResponse(HttpResponseStatus status, String description, String headerName, String example, String headerDescription);
-
- /**
- * Create a blocking handler for the endpoint.
- * The handler will be created "ordered", which means that handlers will not be called concurrently.
- * This should only be used, when absolutely necessary and only for mutating requests.
- * In all other cases, {@link #blockingHandler(Handler, boolean)} with ordered: false should be used.
- *
- * @param requestHandler request handler
- * @return Fluent API
- * @deprecated since requests will only be "ordered" when running in the same http verticle
- */
- InternalEndpointRoute blockingHandler(Handler requestHandler);
-
- /**
- * Create a blocking handler for the endpoint.
- *
- * @param requestHandler request handler
- * @param ordered if the handlers should be called in order or may be called concurrently
- * @return Fluent API
- */
- InternalEndpointRoute blockingHandler(Handler requestHandler, boolean ordered);
-
- /**
- * Create a failure handler for the endpoint.
- *
- * @param failureHandler
- * @return Fluent API
- */
- InternalEndpointRoute failureHandler(Handler failureHandler);
-
- /**
- * Parse the RAML path and return a list of all segment name variables.
- *
- * @return List of path segments
- */
- List getNamedSegments();
-
- /**
- * Set the content type for elements which are returned by the endpoint.
- *
- * @param contentType
- * @return Fluent API
- */
- InternalEndpointRoute produces(String contentType);
-
- /**
- * Set the path using a regex.
- *
- * @param path
- * @return Fluent API
- */
- InternalEndpointRoute pathRegex(String path);
-
- /**
- * Return the path used for RAML. If non null the path which was previously set using {@link #setRAMLPath(String)} will be returned. Otherwise the converted
- * vert.x route path is returned. A vert.x path /:nodeUuid is converted to a RAML path /{nodeUuid}.
- *
- * @return RAML path
- */
- String getRamlPath();
-
- /**
- * Set the endpoint display name.
- *
- * @param name
- * @return Fluent API
- */
- InternalEndpointRoute displayName(String name);
-
- /**
- * Set the endpoint description.
- *
- * @param description
- * Description of the endpoint.
- * @return Fluent API
- */
- InternalEndpointRoute description(String description);
-
- /**
- * Add an uri parameter with description and example to the endpoint.
- *
- * @param key
- * Key of the endpoint (e.g.: query, perPage)
- * @param description
- * @param example
- * Example URI parameter value
- */
- InternalEndpointRoute addUriParameter(String key, String description, String example);
-
- /**
- * Return the uri parameters for the endpoint.
- *
- * @return Map with uri parameters
- */
- Map getUriParameters();
-
- /**
- * Explicitly set the RAML path. This will override the path which is otherwise transformed using the vertx route path.
- *
- * @param path
- */
- InternalEndpointRoute setRAMLPath(String path);
-
- /**
- *
- * @param name
- * @param description
- * @param example
- * @return
- */
- InternalEndpointRoute addQueryParameter(String name, String description, String example);
-
- /**
- * Add a query parameter provider to the endpoint. The query parameter provider will in turn provide examples, descriptions for all query parameters which
- * the parameter provider provides.
- *
- * @param clazz
- * Class which provides the parameters
- * @return Fluent API
- */
- InternalEndpointRoute addQueryParameters(Class extends ParameterProvider> clazz);
-
- /**
- * Return the list of query parameters for the endpoint.
- *
- * @return
- */
- Map getQueryParameters();
-
- /**
- * Return the Vert.x route path regex.
- *
- * @return configured path regex or null if no path regex has been set
- */
- String getPathRegex();
-
- /**
- * Return the endpoint HTTP example request map.
- *
- * @return
- */
- HashMap getExampleRequestMap();
-
- /**
- * Return the map of example responses. The map contains examples per http status code.
- *
- * @return
- */
- Map getExampleResponses();
-
- /**
- * Return the method used for the endpoint.
- *
- * @return
- */
- HttpMethod getMethod();
-
- /**
- * Return the traits which were set for this endpoint.
- *
- * @return
- */
- String[] getTraits();
-
- /**
- * Set the traits information.
- *
- * @param traits
- * Traits which the endpoint should inherit
- * @return Fluent API
- */
- InternalEndpointRoute traits(String... traits);
-
- /**
- * Set the endpoint json example request via the provided json object. The JSON schema will not be generated.
- *
- * @param jsonObject
- * @return Fluent API
- */
- InternalEndpointRoute exampleRequest(JSONObject jsonObject);
-
- /**
- * Set the endpoint example request via a JSON example model. The json schema will automatically be generated.
- *
- * @param model
- * Example Rest Model
- * @return Fluent API
- */
- InternalEndpointRoute exampleRequest(RestModel model);
-
- /**
- * Set the endpoint request example via a form parameter list.
- *
- * @param parameters
- * @return Fluent API
- */
- InternalEndpointRoute exampleRequest(Map> parameters);
-
- /**
- * Set the endpoint request example via a plain text body.
- *
- * @param bodyText
- * @return Fluent API
- */
- InternalEndpointRoute exampleRequest(String bodyText);
-
- /**
- * Return map with status code and the response class.
- *
- * @return
- */
- Map> getExampleResponseClasses();
-
- /**
- * Return the rest model class for the example request.
- *
- * @return
- */
- Class extends RestModel> getExampleRequestClass();
+public interface InternalEndpointRoute extends com.gentics.vertx.openapi.metadata.InternalEndpointRoute {
/**
* Set the events which are emitted by the action of the endpoint.
@@ -409,33 +19,26 @@ public interface InternalEndpointRoute extends Comparable
InternalEndpointRoute events(MeshEvent... events);
/**
- * If true, this endpoint will create, update or delete items in the database.
- * The route will throw an error if this instance is in read only mode.
- *
- * Per default, all POST, DELETE and PUT requests are mutating, other requests are not.
+ * @see com.gentics.vertx.openapi.metadata.InternalEndpointRoute#blockingHandler(Handler)
*
- * @see LocalConfigModel#isReadOnly()
- * @return
+ * @deprecated since requests will only be "ordered" when running in the same http verticle
*/
- boolean isMutating();
+ @Override
+ @Deprecated
+ InternalEndpointRoute blockingHandler(Handler requestHandler);
/**
- * If true, this endpoint will create, update or delete items in the database.
- * The route will throw an error if this instance is in read only mode.
- *
- * Per default, all POST, DELETE and PUT requests are mutating, other requests are not.
- *
- * @see LocalConfigModel#isReadOnly()
- * @param mutating
+ * If true, the endpoint can be used with no authentication.
+ *
* @return
*/
- InternalEndpointRoute setMutating(Boolean mutating);
+ boolean isInsecure();
/**
- * Return underlying route.
+ * Set the endpoint to omit the secure token requirement.
*
+ * @param insecure
* @return
*/
- Route getRoute();
-
+ InternalEndpointRoute setInsecure(boolean insecure);
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/APIRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/APIRouter.java
index 12448d80e9..60a57be4cd 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/APIRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/APIRouter.java
@@ -5,14 +5,7 @@
/**
* Central router for /api/v1 routes
*/
-public interface APIRouter {
-
- /**
- * Internal vert.x router for the API router.
- *
- * @return
- */
- Router getRouter();
+public interface APIRouter extends InternalRouter {
/**
* Return the router to which all projects will be mounted.
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/CustomRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/CustomRouter.java
index 538169e3dc..35151892a6 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/CustomRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/CustomRouter.java
@@ -3,6 +3,6 @@
/**
* Marker interface for custom routers.
*/
-public interface CustomRouter {
+public interface CustomRouter extends InternalRouter {
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/InternalRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/InternalRouter.java
new file mode 100644
index 0000000000..8225ad9486
--- /dev/null
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/InternalRouter.java
@@ -0,0 +1,16 @@
+package com.gentics.mesh.router;
+
+import io.vertx.ext.web.Router;
+
+/**
+ * A base for all internal routers
+ */
+public interface InternalRouter {
+
+ /**
+ * Internal vert.x router for the API router.
+ *
+ * @return
+ */
+ Router getRouter();
+}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/PluginRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/PluginRouter.java
index 1657e5e2cb..6d228adbdd 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/PluginRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/PluginRouter.java
@@ -1,11 +1,13 @@
package com.gentics.mesh.router;
+import java.util.Map;
+
import io.vertx.ext.web.Router;
/**
* Router to track plugin sub routers.
*/
-public interface PluginRouter {
+public interface PluginRouter extends InternalRouter {
/**
* Remove the plugin router.
@@ -22,4 +24,10 @@ public interface PluginRouter {
*/
void addRouter(String name, Router pluginRouter);
+ /**
+ * Get currently registered routers.
+ *
+ * @return immutable name/router map
+ */
+ Map pluginRouters();
}
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/ProjectRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/ProjectRouter.java
index 7f4abbd90f..aa14048040 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/ProjectRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/ProjectRouter.java
@@ -7,14 +7,7 @@
/**
* This class manages the project routers (e.g. routers for endpoints like :apibase:/:projectName/nodes)
*/
-public interface ProjectRouter {
-
- /**
- * Return the Vert.x router.
- *
- * @return
- */
- Router getRouter();
+public interface ProjectRouter extends InternalRouter {
/**
* Return all routers that have been registered.
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/ProjectsRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/ProjectsRouter.java
index c12a9ca330..a78a6fa52e 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/ProjectsRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/ProjectsRouter.java
@@ -6,7 +6,7 @@
import io.vertx.ext.web.Router;
-public interface ProjectsRouter {
+public interface ProjectsRouter extends InternalRouter {
/**
* Common router which holds project specific routes (e.g: /nodes /tagFamilies)
diff --git a/mdm/api/src/main/java/com/gentics/mesh/router/RootRouter.java b/mdm/api/src/main/java/com/gentics/mesh/router/RootRouter.java
index ea72c30611..52f91c9202 100644
--- a/mdm/api/src/main/java/com/gentics/mesh/router/RootRouter.java
+++ b/mdm/api/src/main/java/com/gentics/mesh/router/RootRouter.java
@@ -1,11 +1,9 @@
package com.gentics.mesh.router;
-import io.vertx.ext.web.Router;
-
/**
* The root router is the top level router of the routing stack.
*/
-public interface RootRouter {
+public interface RootRouter extends InternalRouter {
/**
* Return the /api/v1 router
@@ -14,13 +12,6 @@ public interface RootRouter {
*/
APIRouter apiRouter();
- /**
- * Return the Vert.x router.
- *
- * @return
- */
- Router getRouter();
-
/**
* Return the central router storage.
*
diff --git a/mdm/common/src/main/java/com/gentics/mesh/example/MiscExamples.java b/mdm/common/src/main/java/com/gentics/mesh/example/MiscExamples.java
index 1155d66e77..405e53a27a 100644
--- a/mdm/common/src/main/java/com/gentics/mesh/example/MiscExamples.java
+++ b/mdm/common/src/main/java/com/gentics/mesh/example/MiscExamples.java
@@ -4,10 +4,8 @@
import java.util.Map;
import java.util.stream.Stream;
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
-
import com.gentics.mesh.core.rest.auth.LoginRequest;
+import com.gentics.mesh.core.rest.auth.TokenResponse;
import com.gentics.mesh.core.rest.common.GenericMessageResponse;
import com.gentics.mesh.core.rest.search.EntityMetrics;
import com.gentics.mesh.core.rest.search.SearchStatusResponse;
@@ -62,29 +60,20 @@ public GenericMessageResponse createMessageResponse() {
return message;
}
- public JSONObject getSearchQueryExample() {
- JSONObject node = new JSONObject();
- try {
- JSONObject query = new JSONObject();
- JSONObject queryString = new JSONObject();
- queryString.put("query", "some name");
- query.put("query_string", queryString);
- node.put("query", query);
- } catch (JSONException e) {
- e.printStackTrace();
- }
+ public JsonObject getSearchQueryExample() {
+ JsonObject node = new JsonObject();
+ JsonObject query = new JsonObject();
+ JsonObject queryString = new JsonObject();
+ queryString.put("query", "some name");
+ query.put("query_string", queryString);
+ node.put("query", query);
return node;
}
- public JSONObject getAuthTokenResponse() {
- JSONObject node = new JSONObject();
- try {
- node.put("token",
- "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyVXVpZCI6IlVVSURPRlVTRVIxIiwiZXhwIjoxNDY5MTE3MjQ3LCJpYXQiOjE0NjkxMTM2NDd9.i1u4RMs4K7zBkGhmcpp1P79Wpz2UQYJkZKJTVdFp_iU=");
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return node;
+ public TokenResponse getAuthTokenResponse() {
+ TokenResponse response = new TokenResponse();
+ response.setToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyVXVpZCI6IlVVSURPRlVTRVIxIiwiZXhwIjoxNDY5MTE3MjQ3LCJpYXQiOjE0NjkxMTM2NDd9.i1u4RMs4K7zBkGhmcpp1P79Wpz2UQYJkZKJTVdFp_iU=");
+ return response;
}
public JsonObject createSearchResponse() {
diff --git a/mdm/common/src/main/java/com/gentics/mesh/example/NodeExamples.java b/mdm/common/src/main/java/com/gentics/mesh/example/NodeExamples.java
index 241bb0bca7..c34b7fc27e 100644
--- a/mdm/common/src/main/java/com/gentics/mesh/example/NodeExamples.java
+++ b/mdm/common/src/main/java/com/gentics/mesh/example/NodeExamples.java
@@ -40,6 +40,7 @@
import com.gentics.mesh.MeshVersion;
import com.gentics.mesh.core.rest.navigation.NavigationElement;
import com.gentics.mesh.core.rest.navigation.NavigationResponse;
+import com.gentics.mesh.core.rest.node.BinaryCheckUpdateRequest;
import com.gentics.mesh.core.rest.node.FieldMap;
import com.gentics.mesh.core.rest.node.FieldMapImpl;
import com.gentics.mesh.core.rest.node.NodeChildrenInfo;
@@ -48,6 +49,7 @@
import com.gentics.mesh.core.rest.node.NodeResponse;
import com.gentics.mesh.core.rest.node.NodeUpdateRequest;
import com.gentics.mesh.core.rest.node.PublishStatusModel;
+import com.gentics.mesh.core.rest.node.field.BinaryCheckStatus;
import com.gentics.mesh.core.rest.node.field.BinaryField;
import com.gentics.mesh.core.rest.node.field.BinaryFieldTransformRequest;
import com.gentics.mesh.core.rest.node.field.Field;
@@ -60,6 +62,7 @@
import com.gentics.mesh.core.rest.node.field.impl.HtmlFieldImpl;
import com.gentics.mesh.core.rest.node.field.impl.NumberFieldImpl;
import com.gentics.mesh.core.rest.node.field.impl.StringFieldImpl;
+import com.gentics.mesh.core.rest.node.field.s3binary.S3BinaryUploadRequest;
import com.gentics.mesh.core.rest.node.version.NodeVersionsResponse;
import com.gentics.mesh.core.rest.node.version.VersionInfo;
import com.gentics.mesh.core.rest.schema.impl.SchemaReferenceImpl;
@@ -334,22 +337,18 @@ public Map> getExampleBinaryUploadFormParameters() {
return parameters;
}
- public Map> getExampleBinaryCheckCallbackParameters() {
- Map> parameters = new HashMap<>();
- FormParameter statusParameter = new FormParameter();
- statusParameter.setExample("DENIED");
- statusParameter.setType(ParamType.STRING);
- statusParameter.setDescription("The result of the binary check. One of ACCEPTED or DENIED.");
- statusParameter.setRequired(true);
- parameters.put("status", Arrays.asList(statusParameter));
-
- FormParameter reasonParameter = new FormParameter();
- reasonParameter.setExample("Malware detected");
- reasonParameter.setType(ParamType.STRING);
- reasonParameter.setDescription("The reason why the binary was denied.");
- reasonParameter.setRequired(false);
- parameters.put("reason", Arrays.asList(reasonParameter));
+ public S3BinaryUploadRequest getExampleS3BinaryUploadFormParameters() {
+ S3BinaryUploadRequest parameters = new S3BinaryUploadRequest();
+ parameters.setVersion("1.0");
+ parameters.setLanguage("en");
+ parameters.setFilename("blumen/blume.jpg");
+ return parameters;
+ }
+ public BinaryCheckUpdateRequest getExampleBinaryCheckCallbackParameters() {
+ BinaryCheckUpdateRequest parameters = new BinaryCheckUpdateRequest();
+ parameters.setStatus(BinaryCheckStatus.DENIED);
+ parameters.setReason("Malware detected");
return parameters;
}
diff --git a/mdm/common/src/main/java/com/gentics/mesh/example/SchemaExamples.java b/mdm/common/src/main/java/com/gentics/mesh/example/SchemaExamples.java
index 20b5b7e337..4a769e0fae 100644
--- a/mdm/common/src/main/java/com/gentics/mesh/example/SchemaExamples.java
+++ b/mdm/common/src/main/java/com/gentics/mesh/example/SchemaExamples.java
@@ -7,6 +7,7 @@
import static com.gentics.mesh.core.rest.schema.change.impl.SchemaChangeOperation.UPDATEFIELD;
import static com.gentics.mesh.example.ExampleUuids.UUID_1;
+import com.gentics.mesh.core.rest.common.GenericMessageResponse;
import com.gentics.mesh.core.rest.schema.HtmlFieldSchema;
import com.gentics.mesh.core.rest.schema.ListFieldSchema;
import com.gentics.mesh.core.rest.schema.MicronodeFieldSchema;
diff --git a/mdm/hibernate-api/src/main/java/com/gentics/mesh/etc/config/HibernateMeshOptions.java b/mdm/hibernate-api/src/main/java/com/gentics/mesh/etc/config/HibernateMeshOptions.java
index 49e934b403..ab4bd05d07 100644
--- a/mdm/hibernate-api/src/main/java/com/gentics/mesh/etc/config/HibernateMeshOptions.java
+++ b/mdm/hibernate-api/src/main/java/com/gentics/mesh/etc/config/HibernateMeshOptions.java
@@ -123,4 +123,22 @@ public void setLicenseKeyPath(String licenseKeyPath) {
public boolean hasDatabaseLevelCache() {
return true;
}
+
+ @Override
+ @JsonIgnore
+ public Version getDefaultOpenAPIVersion() {
+ return Version.V30;
+ }
+
+ @Override
+ @JsonIgnore
+ public Format getDefaultOpenAPIFormat() {
+ return Format.YAML;
+ }
+
+ @Override
+ @JsonIgnore
+ public String getNoApiInfoPlugins() {
+ return null;
+ }
}
diff --git a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/AdminEndpointProviderModule.java b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/EndpointProviderModule.java
similarity index 78%
rename from mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/AdminEndpointProviderModule.java
rename to mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/EndpointProviderModule.java
index 974b472272..3fb64ab83f 100644
--- a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/AdminEndpointProviderModule.java
+++ b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/EndpointProviderModule.java
@@ -13,6 +13,7 @@
import com.gentics.mesh.core.endpoint.admin.JobHandler;
import com.gentics.mesh.core.endpoint.admin.LocalConfigApi;
import com.gentics.mesh.core.endpoint.admin.LocalConfigHandler;
+import com.gentics.mesh.core.endpoint.admin.RestInfoEndpoint;
import com.gentics.mesh.core.endpoint.admin.ShutdownHandler;
import com.gentics.mesh.core.endpoint.admin.consistency.ConsistencyCheckHandler;
import com.gentics.mesh.core.endpoint.admin.debuginfo.DebugInfoHandler;
@@ -21,6 +22,7 @@
import com.gentics.mesh.core.verticle.handler.WriteLock;
import com.gentics.mesh.distributed.coordinator.Coordinator;
import com.gentics.mesh.endpoint.admin.HibAdminHandler;
+import com.gentics.mesh.etc.config.HibernateMeshOptions;
import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.router.RouterStorageImpl;
import com.gentics.mesh.router.RouterStorageRegistryImpl;
@@ -31,7 +33,21 @@
import io.vertx.core.Vertx;
@Module
-public class AdminEndpointProviderModule {
+public class EndpointProviderModule {
+
+ @Provides
+ public static HibernateMeshOptions hibernateMeshOptions(MeshOptions meshOptions) {
+ if (meshOptions instanceof HibernateMeshOptions) {
+ return (HibernateMeshOptions) meshOptions;
+ } else {
+ throw new IllegalArgumentException("Unsupported MeshOptions class:" + meshOptions.getClass().getCanonicalName());
+ }
+ }
+
+ @Provides
+ public static RestInfoEndpoint provideRestInfoEndpoint(MeshAuthChain chain, AdminHandler adminHandler, LocalConfigApi localConfigApi, Database db, MeshOptions options) {
+ return new RestInfoEndpoint(chain, adminHandler, localConfigApi, db, options);
+ }
@Provides
public static AdminEndpoint provideAdminEndpoint(MeshAuthChain chain, AdminHandler adminHandler, JobHandler jobHandler,
diff --git a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateMeshComponent.java b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateMeshComponent.java
index bb25bc406e..98157a48b7 100644
--- a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateMeshComponent.java
+++ b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateMeshComponent.java
@@ -22,7 +22,7 @@
* Central dagger mesh component which will expose dependencies.
*/
@Singleton
-@Component(modules = { CommonModule.class, HibernateModule.class, SearchWaitUtilProviderModule.class, AdminEndpointProviderModule.class, DatabaseConnectorModule.class, AuthChainProviderModule.class })
+@Component(modules = { CommonModule.class, HibernateModule.class, SearchWaitUtilProviderModule.class, EndpointProviderModule.class, DatabaseConnectorModule.class, AuthChainProviderModule.class })
public interface HibernateMeshComponent extends MeshComponent {
@Getter
diff --git a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateModule.java b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateModule.java
index 785dd0e446..0a7f7b6913 100644
--- a/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateModule.java
+++ b/mdm/hibernate-core/src/main/java/com/gentics/mesh/dagger/HibernateModule.java
@@ -93,8 +93,6 @@
import com.gentics.mesh.database.cluster.HibClusterManager;
import com.gentics.mesh.distributed.MasterInfoProvider;
import com.gentics.mesh.distributed.MasterInfoProviderImpl;
-import com.gentics.mesh.etc.config.HibernateMeshOptions;
-import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.hibernate.HibernateRootResolver;
import com.gentics.mesh.hibernate.data.binary.impl.HibBinariesImpl;
import com.gentics.mesh.hibernate.data.dao.BinaryDaoImpl;
@@ -292,15 +290,6 @@ public abstract class HibernateModule {
@Binds
abstract S3Binaries bindS3Binaries(S3HibBinariesImpl e);
- @Provides
- public static HibernateMeshOptions hibernateMeshOptions(MeshOptions meshOptions) {
- if (meshOptions instanceof HibernateMeshOptions) {
- return (HibernateMeshOptions) meshOptions;
- } else {
- throw new IllegalArgumentException("Unsupported MeshOptions class:" + meshOptions.getClass().getCanonicalName());
- }
- }
-
@Provides
@Singleton
public static HazelcastInstance hazelcast(HibClusterManager clusterManager) {
diff --git a/mdm/hibernate-core/src/main/java/com/gentics/mesh/database/cluster/HibClusterManager.java b/mdm/hibernate-core/src/main/java/com/gentics/mesh/database/cluster/HibClusterManager.java
index be40844990..5fcdacc087 100644
--- a/mdm/hibernate-core/src/main/java/com/gentics/mesh/database/cluster/HibClusterManager.java
+++ b/mdm/hibernate-core/src/main/java/com/gentics/mesh/database/cluster/HibClusterManager.java
@@ -6,6 +6,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -57,7 +58,7 @@ public HazelcastInstance getHazelcast() {
config = new Config();
}
config.setInstanceName(options.getNodeName());
- config.setClusterName(options.getClusterOptions().getClusterName());
+ config.setClusterName(Optional.ofNullable(options.getClusterOptions().getClusterName()).orElseGet(() -> options.getNodeName()));
config.setClassLoader(Thread.currentThread().getContextClassLoader());
config.getMemberAttributeConfig().setAttribute("__vertx.nodeId", options.getNodeName());
hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance(config);
diff --git a/mdm/hibernate-core/src/main/java/com/gentics/mesh/endpoint/admin/HibAdminHandler.java b/mdm/hibernate-core/src/main/java/com/gentics/mesh/endpoint/admin/HibAdminHandler.java
index c26117a232..4cf6afbdce 100644
--- a/mdm/hibernate-core/src/main/java/com/gentics/mesh/endpoint/admin/HibAdminHandler.java
+++ b/mdm/hibernate-core/src/main/java/com/gentics/mesh/endpoint/admin/HibAdminHandler.java
@@ -4,8 +4,24 @@
import static com.gentics.mesh.core.rest.error.Errors.error;
import static com.gentics.mesh.rest.Messages.message;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.gentics.mesh.MeshVersion;
import com.gentics.mesh.cache.CacheRegistry;
import com.gentics.mesh.cli.BootstrapInitializer;
import com.gentics.mesh.contentoperation.ContentCachedStorage;
@@ -17,10 +33,16 @@
import com.gentics.mesh.core.verticle.handler.HandlerUtilities;
import com.gentics.mesh.core.verticle.handler.WriteLock;
import com.gentics.mesh.distributed.coordinator.Coordinator;
+import com.gentics.mesh.etc.config.HttpServerConfig;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.etc.config.Version;
+import com.gentics.mesh.http.HttpConstants;
import com.gentics.mesh.router.RouterStorageImpl;
import com.gentics.mesh.router.RouterStorageRegistryImpl;
import com.gentics.mesh.search.SearchProvider;
+import com.gentics.mesh.util.MeshOpenAPIv3Generator;
+import com.gentics.vertx.openapi.model.Format;
+import com.gentics.vertx.openapi.model.OpenAPIGenerationException;
import io.vertx.core.Vertx;
@@ -57,4 +79,56 @@ public void handleCacheClear(InternalActionContext ac) {
return message(ac, "cache_clear_invoked");
}, model -> ac.send(model, OK));
}
+
+ @Override
+ public void handleOpenAPIv3(InternalActionContext ac, com.gentics.mesh.etc.config.Format formatConf, Version version) {
+ boolean useVersion31 = version == Version.V31;
+ String format = formatConf.name().toLowerCase();
+
+ // Collect available servers
+ HttpServerConfig httpServerConfig = options.getHttpServerOptions();
+ List servers = Collections.singletonList((httpServerConfig.isSsl() ? "https://" : "http://") + httpServerConfig.getHost() + ":" + (httpServerConfig.isSsl() ? httpServerConfig.getSslPort() : httpServerConfig.getPort()));
+
+ /*
+ * Blacklist
+ * a) all the actual project roots
+ * b) old api version roots
+ * c) an `apiversion` selector parameter root
+ * d) plugin paths
+ */
+ Set blacklistedRouteRegex = new HashSet<>(routerStorageRegistry.getInstances().stream()
+ .flatMap(rr -> rr.root().apiRouter().projectsRouter().getProjectRouters().keySet().stream())
+ .map(project -> "\\/api\\/v" + MeshVersion.CURRENT_API_VERSION + "\\/" + project + "[.]*").collect(Collectors.toSet()));
+ blacklistedRouteRegex.addAll(IntStream.range(1, MeshVersion.CURRENT_API_VERSION).mapToObj(v -> "\\/api\\/v" + v + "[.]*").collect(Collectors.toList()));
+ blacklistedRouteRegex.addAll(List.of("\\/api\\/\\{apiversion\\}[.]*", "\\/api\\/v" + MeshVersion.CURRENT_API_VERSION + "\\/eventbus\\/"));
+ blacklistedRouteRegex.addAll(List.of("\\/api\\/v" + MeshVersion.CURRENT_API_VERSION + "\\/\\{project\\}\\/plugins[.]*", "\\/api\\/v" + MeshVersion.CURRENT_API_VERSION + "\\/plugins[.]*"));
+
+ // Make an instance with blacklist path patterns
+ MeshOpenAPIv3Generator generator = new MeshOpenAPIv3Generator(MeshVersion.getPlainVersion(), servers, Optional.of(blacklistedRouteRegex.stream().map(Pattern::compile).collect(Collectors.toList())), Optional.empty());
+
+ // Generate...
+ try {
+ ac.send(generator.generate(
+ "Gentics Mesh REST API",
+ Stream.of(
+ //... from base root
+ routerStorageRegistry.getInstances().stream().map(rr -> Pair.of(rr.root().getRouter(), StringUtils.EMPTY)),
+ //... from generic project root
+ routerStorageRegistry.getInstances().stream().map(rr -> Pair.of(rr.root().apiRouter().projectsRouter().projectRouter().getRouter(), "/api/v" + MeshVersion.CURRENT_API_VERSION + "/{project}"))
+ ).flatMap(Function.identity()).collect(Collectors.toMap(Pair::getKey, Pair::getValue)),
+ // ...with desired format
+ Format.parse(format),
+ // ...with desired pretty printing
+ !options.getHttpServerOptions().isMinifyJson(),
+ // ...with desired spec version
+ useVersion31),
+ OK,
+ "yaml".equalsIgnoreCase(format)
+ ? HttpConstants.APPLICATION_YAML_UTF8
+ : HttpConstants.APPLICATION_JSON_UTF8
+ );
+ } catch (OpenAPIGenerationException e) {
+ ac.fail(error(INTERNAL_SERVER_ERROR, "error_internal", e));
+ }
+ }
}
diff --git a/plugin-api/src/main/java/com/gentics/mesh/plugin/RestPlugin.java b/plugin-api/src/main/java/com/gentics/mesh/plugin/RestPlugin.java
index 095fc4f70f..a28e91f05a 100644
--- a/plugin-api/src/main/java/com/gentics/mesh/plugin/RestPlugin.java
+++ b/plugin-api/src/main/java/com/gentics/mesh/plugin/RestPlugin.java
@@ -8,6 +8,8 @@
import java.util.Optional;
import java.util.concurrent.Callable;
+import org.apache.commons.lang3.tuple.Pair;
+
import com.gentics.mesh.etc.config.MeshOptions;
import com.gentics.mesh.etc.config.VertxOptions;
@@ -45,6 +47,15 @@ default Router createProjectRouter() {
return null;
}
+ /**
+ * Create a pair of routers, global and project. Note that this method will be invoked multiple times in order to register the endpoints to all REST verticles.
+ *
+ * @return
+ */
+ default Pair createRouters() {
+ return Pair.of(createGlobalRouter(), createProjectRouter());
+ }
+
/**
* Return a wrapped routing context.
*
diff --git a/plugin-parent/pom.xml b/plugin-parent/pom.xml
index 90129d2d06..48d51e0b52 100644
--- a/plugin-parent/pom.xml
+++ b/plugin-parent/pom.xml
@@ -42,6 +42,37 @@
mesh-plugin-api
provided
+
+ com.gentics
+ vertx-openapi
+ provided
+
+
+ org.slf4j
+ slf4j-parent
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ org.slf4j
+ slf4j-api
+
+
+ commons-validator
+ commons-validator
+
+
+ com.github.fge
+ json-schema-validator
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+
+
+
diff --git a/rest-client/src/main/java/com/gentics/mesh/parameter/client/AbstractParameters.java b/rest-client/src/main/java/com/gentics/mesh/parameter/client/AbstractParameters.java
index 4832753e2e..e9600b36c3 100644
--- a/rest-client/src/main/java/com/gentics/mesh/parameter/client/AbstractParameters.java
+++ b/rest-client/src/main/java/com/gentics/mesh/parameter/client/AbstractParameters.java
@@ -5,11 +5,10 @@
import org.raml.model.parameter.QueryParameter;
-import com.gentics.mesh.parameter.PagingParameters;
import com.gentics.mesh.parameter.ParameterProvider;
/**
- * Common default implementation for {@link PagingParameters}
+ * Common default implementation for {@link ParameterProvider}
*/
public abstract class AbstractParameters implements ParameterProvider {
diff --git a/rest-client/src/main/java/com/gentics/mesh/parameter/client/EtagParametersImpl.java b/rest-client/src/main/java/com/gentics/mesh/parameter/client/EtagParametersImpl.java
new file mode 100644
index 0000000000..73d6d6f456
--- /dev/null
+++ b/rest-client/src/main/java/com/gentics/mesh/parameter/client/EtagParametersImpl.java
@@ -0,0 +1,10 @@
+package com.gentics.mesh.parameter.client;
+
+import com.gentics.mesh.parameter.EtagParameters;
+
+/**
+ * @see EtagParameters
+ */
+public class EtagParametersImpl extends AbstractParameters implements EtagParameters {
+
+}
diff --git a/rest-client/src/main/java/com/gentics/mesh/parameter/client/GenericParametersImpl.java b/rest-client/src/main/java/com/gentics/mesh/parameter/client/GenericParametersImpl.java
index 86226f30a2..43a290e512 100644
--- a/rest-client/src/main/java/com/gentics/mesh/parameter/client/GenericParametersImpl.java
+++ b/rest-client/src/main/java/com/gentics/mesh/parameter/client/GenericParametersImpl.java
@@ -5,6 +5,6 @@
/**
* @see GenericParameters
*/
-public class GenericParametersImpl extends AbstractParameters implements GenericParameters {
+public class GenericParametersImpl extends EtagParametersImpl implements GenericParameters {
}
diff --git a/rest-client/src/main/java/com/gentics/mesh/parameter/client/LanguageParametersImpl.java b/rest-client/src/main/java/com/gentics/mesh/parameter/client/LanguageParametersImpl.java
new file mode 100644
index 0000000000..787c0175f8
--- /dev/null
+++ b/rest-client/src/main/java/com/gentics/mesh/parameter/client/LanguageParametersImpl.java
@@ -0,0 +1,7 @@
+package com.gentics.mesh.parameter.client;
+
+import com.gentics.mesh.parameter.LanguageParameters;
+
+public class LanguageParametersImpl extends AbstractParameters implements LanguageParameters {
+
+}
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/MeshRestClientMessageException.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/MeshRestClientMessageException.java
index d49a6e292c..63b5503589 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/MeshRestClientMessageException.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/MeshRestClientMessageException.java
@@ -33,7 +33,7 @@ public MeshRestClientMessageException(int statusCode, String statusMessage, Stri
}
public MeshRestClientMessageException(int statusCode, String statusMessage, GenericMessageResponse responseMessage, HttpMethod method, String uri) {
- super("Error:" + statusCode + " in " + method.name() + " " + uri + " : " + statusMessage);
+ super("Error:" + statusCode + (method != null ? (" in " + method.name()) : "") + " " + uri + " : " + statusMessage);
this.responseMessage = responseMessage;
this.statusCode = statusCode;
this.uri = uri;
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/AbstractMeshOkHttpRequest.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/AbstractMeshOkHttpRequest.java
new file mode 100644
index 0000000000..2647350b09
--- /dev/null
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/AbstractMeshOkHttpRequest.java
@@ -0,0 +1,193 @@
+package com.gentics.mesh.rest.client.impl;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.gentics.mesh.core.rest.common.GenericMessageResponse;
+import com.gentics.mesh.core.rest.error.GenericRestException;
+import com.gentics.mesh.json.JsonUtil;
+import com.gentics.mesh.rest.client.MeshBinaryResponse;
+import com.gentics.mesh.rest.client.MeshRequest;
+import com.gentics.mesh.rest.client.MeshResponse;
+import com.gentics.mesh.rest.client.MeshRestClientMessageException;
+import com.gentics.mesh.rest.client.MeshWebrootFieldResponse;
+import com.gentics.mesh.rest.client.MeshWebrootResponse;
+
+import io.reactivex.Completable;
+import io.reactivex.Single;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+/**
+ * Default OkHTTP based client implementation
+ *
+ * @param
+ */
+public abstract class AbstractMeshOkHttpRequest implements MeshRequest {
+
+ protected final OkHttpClient client;
+ protected final Class extends R> resultClass;
+
+ public AbstractMeshOkHttpRequest(OkHttpClient client, Class extends R> resultClass) {
+ this.client = client;
+ this.resultClass = resultClass;
+ }
+
+ @Override
+ public Single> getResponse() {
+ return getOkResponse().map(response -> new MeshResponse() {
+ Supplier body = Util.lazily(() -> mapResponse(response));
+
+ @Override
+ public Map> getHeaders() {
+ return response.headers().toMultimap();
+ }
+
+ @Override
+ public List getHeaders(String name) {
+ return response.headers(name);
+ }
+
+ @Override
+ public int getStatusCode() {
+ return response.code();
+ }
+
+ @Override
+ public String getBodyAsString() {
+ try {
+ return response.body().string();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public R getBody() {
+ return body.get();
+ }
+
+ @Override
+ public void close() {
+ Optional.ofNullable(response).map(Response::body).ifPresent(ResponseBody::close);
+ }
+ });
+ }
+
+ @Override
+ public Completable toCompletable() {
+ return getOkResponse()
+ .doOnSuccess(this::throwOnError)
+ .doOnSuccess(response -> Optional.ofNullable(response)
+ .ifPresent(Response::close))
+ .ignoreElement();
+ }
+
+ @Override
+ public Single toSingle() {
+ return getOkResponse().map(this::mapResponse);
+ }
+
+ public Single getOkResponse() {
+ return Single.create(sub -> {
+ Call call = createCall();
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ // Don't call the onError twice, but notify about multiple exceptions (should not occur often).
+ if (sub.isDisposed()) {
+ e.printStackTrace();
+ } else {
+ sub.onError(new IOException(String.format("I/O Error in %s %s : %s (%s)",
+ HttpMethod.valueOf(call.request().method().toUpperCase()), call.request().url(), e.getClass().getSimpleName(), e.getLocalizedMessage()), e));
+ }
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ if (!sub.isDisposed()) {
+ sub.onSuccess(response);
+ } else {
+ response.close();
+ }
+ }
+ });
+ });
+ }
+
+ protected abstract Request createRequest();
+
+ protected Call createCall() {
+ return client.newCall(createRequest());
+ }
+
+ @SuppressWarnings("unchecked")
+ private R mapResponse(Response response) throws IOException, MeshRestClientMessageException {
+ throwOnError(response);
+
+ String contentType = response.header("Content-Type");
+ if (!response.isSuccessful()) {
+ return null;
+ } else if (resultClass.isAssignableFrom(EmptyResponse.class)) {
+ return (R) EmptyResponse.getInstance();
+ } else if (resultClass.isAssignableFrom(MeshBinaryResponse.class)) {
+ return (R) new OkHttpBinaryResponse(response);
+ } else if (resultClass.isAssignableFrom(MeshWebrootResponse.class)) {
+ return (R) new OkHttpWebrootResponse(response);
+ } else if (resultClass.isAssignableFrom(MeshWebrootFieldResponse.class)) {
+ return (R) new OkHttpWebrootFieldResponse(response, false);
+ } else if (contentType != null && contentType.startsWith("application/json") && !resultClass.isAssignableFrom(String.class)) {
+ return JsonUtil.readValue(response.body().string(), resultClass);
+ } else if (resultClass.isAssignableFrom(String.class)) {
+ return (R) response.body().string();
+ } else {
+ throw new RuntimeException("Request can't be handled by this handler since the content type was {" + contentType + "}");
+ }
+ }
+
+ private void throwOnError(Response response) throws IOException, MeshRestClientMessageException {
+ if (!response.isSuccessful() && response.code() != 304) {
+ String body = response.body().string();
+ MeshRestClientMessageException err;
+ try {
+ GenericMessageResponse msg = null;
+ if (!StringUtils.isEmpty(body)) {
+ msg = JsonUtil.readValue(body, GenericMessageResponse.class);
+ }
+ err = new MeshRestClientMessageException(
+ response.code(),
+ response.message(),
+ msg,
+ HttpMethod.valueOf(response.request().method().toUpperCase()),
+ stripOrigin(response.request().url().toString()));
+ } catch (GenericRestException e) {
+ err = new MeshRestClientMessageException(
+ response.code(),
+ response.message(),
+ body,
+ HttpMethod.valueOf(response.request().method().toUpperCase()),
+ stripOrigin(response.request().url().toString()));
+ }
+ response.close();
+ throw err;
+ }
+ }
+
+ private String stripOrigin(String url) {
+ URI uri = URI.create(url);
+ String query = uri.getQuery();
+ return uri.getPath() + (query == null || query.length() == 0
+ ? ""
+ : "?" + query);
+ }
+}
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshOkHttpRequestImpl.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshOkHttpRequestImpl.java
index e63e1b6e87..a9ad5163bd 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshOkHttpRequestImpl.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshOkHttpRequestImpl.java
@@ -27,7 +27,6 @@
import com.gentics.mesh.rest.client.MeshWebrootFieldResponse;
import com.gentics.mesh.rest.client.MeshWebrootResponse;
-import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.Single;
@@ -53,12 +52,10 @@
* @see MeshRequest
* @param
*/
-public class MeshOkHttpRequestImpl implements MeshRequest {
+public class MeshOkHttpRequestImpl extends AbstractMeshOkHttpRequest {
private final MeshRestClient meshClient;
- private final OkHttpClient client;
private final MeshRestClientConfig config;
- private final Class extends T> resultClass;
private final String method;
private final String url;
@@ -67,10 +64,9 @@ public class MeshOkHttpRequestImpl implements MeshRequest {
private MeshOkHttpRequestImpl(MeshRestClient meshClient, OkHttpClient client, MeshRestClientConfig config, Class extends T> resultClass, String method, String url, Map headers,
RequestBody requestBody) {
+ super(client, resultClass);
this.meshClient = meshClient;
- this.client = client;
this.config = config;
- this.resultClass = resultClass;
this.method = method;
this.url = url;
this.headers = headers;
@@ -200,7 +196,8 @@ public void setHeaders(Map headers) {
this.headers.putAll(headers);
}
- private Request createRequest() {
+ @Override
+ protected Request createRequest() {
Request.Builder builder = new Request.Builder()
.url(url)
.headers(Headers.of(headers));
@@ -265,20 +262,6 @@ public void onResponse(Call call, Response response) throws IOException {
return response.retryWhen(retryOnNetworkErrors(retries, delay));
}
- @Override
- public Single toSingle() {
- return getOkResponse().map(this::mapResponse);
- }
-
- @Override
- public Completable toCompletable() {
- return getOkResponse()
- .doOnSuccess(this::throwOnError)
- .doOnSuccess(response -> Optional.ofNullable(response)
- .ifPresent(Response::close))
- .ignoreElement();
- }
-
@SuppressWarnings("unchecked")
private T mapResponse(Response response) throws IOException, MeshRestClientMessageException {
throwOnError(response);
@@ -309,7 +292,7 @@ private T mapResponse(Response response) throws IOException, MeshRestClientMessa
return (T) new OkHttpWebrootResponse(response);
} else if (resultClass.isAssignableFrom(MeshWebrootFieldResponse.class)) {
return (T) new OkHttpWebrootFieldResponse(response, config.isMinifyJson());
- } else if (contentType != null && contentType.startsWith("application/json")) {
+ } else if (contentType != null && contentType.startsWith("application/json") && !resultClass.isAssignableFrom(String.class)) {
return JsonUtil.readValue(response.body().string(), resultClass);
} else if (resultClass.isAssignableFrom(String.class)) {
return (T) response.body().string();
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java
index e71cdf1c27..479f7ef8bb 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java
@@ -105,7 +105,6 @@
import com.gentics.mesh.core.rest.user.UserResponse;
import com.gentics.mesh.core.rest.user.UserUpdateRequest;
import com.gentics.mesh.core.rest.validation.SchemaValidationResponse;
-import com.gentics.mesh.parameter.BackupParameters;
import com.gentics.mesh.parameter.ImageManipulationParameters;
import com.gentics.mesh.parameter.PagingParameters;
import com.gentics.mesh.parameter.ParameterProvider;
@@ -281,12 +280,12 @@ public MeshRequest findTagByUuid(String projectName, String tagFami
}
@Override
- public MeshRequest updateTag(String projectName, String tagFamilyUuid, String uuid, TagUpdateRequest tagUpdateRequest) {
+ public MeshRequest updateTag(String projectName, String tagFamilyUuid, String uuid, TagUpdateRequest tagUpdateRequest, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Objects.requireNonNull(tagUpdateRequest, "tagUpdateRequest must not be null");
Util.requireUuid(tagFamilyUuid, "tagFamilyUuid");
Util.requireUuid(uuid, "uuid");
- return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/tags/" + uuid, TagResponse.class,
+ return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/tags/" + uuid + getQuery(getConfig(), parameters), TagResponse.class,
tagUpdateRequest);
}
@@ -420,13 +419,13 @@ public MeshRequest findProjects(ParameterProvider... parame
}
@Override
- public MeshRequest assignLanguageToProject(String projectUuid, String languageUuid) {
- return assignLanguageToProjectByUuid(projectUuid, languageUuid);
+ public MeshRequest assignLanguageToProject(String projectUuid, String languageUuid, ParameterProvider... parameters) {
+ return assignLanguageToProjectByUuid(projectUuid, languageUuid, parameters);
}
@Override
- public MeshRequest unassignLanguageFromProject(String projectUuid, String languageUuid) {
- return unassignLanguageFromProjectByUuid(projectUuid, languageUuid);
+ public MeshRequest unassignLanguageFromProject(String projectUuid, String languageUuid, ParameterProvider... parameters) {
+ return unassignLanguageFromProjectByUuid(projectUuid, languageUuid, parameters);
}
@Override
@@ -443,10 +442,10 @@ public MeshRequest createProject(String uuid, ProjectCreateRequ
}
@Override
- public MeshRequest updateProject(String uuid, ProjectUpdateRequest projectUpdateRequest) {
+ public MeshRequest updateProject(String uuid, ProjectUpdateRequest projectUpdateRequest, ParameterProvider... parameters) {
Util.requireUuid(uuid, "uuid");
Objects.requireNonNull(projectUpdateRequest, "projectUpdateRequest must not be null");
- return prepareRequest(POST, "/projects/" + uuid, ProjectResponse.class, projectUpdateRequest);
+ return prepareRequest(POST, "/projects/" + uuid + getQuery(getConfig(), parameters), ProjectResponse.class, projectUpdateRequest);
}
@Override
@@ -529,11 +528,11 @@ public MeshRequest deleteTagFamily(String projectName, String uui
}
@Override
- public MeshRequest updateTagFamily(String projectName, String tagFamilyUuid, TagFamilyUpdateRequest tagFamilyUpdateRequest) {
+ public MeshRequest updateTagFamily(String projectName, String tagFamilyUuid, TagFamilyUpdateRequest tagFamilyUpdateRequest, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Util.requireUuid(tagFamilyUuid, "tagFamilyUuid");
Objects.requireNonNull(tagFamilyUpdateRequest, "tagFamilyUpdateRequest must not be null");
- return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid, TagFamilyResponse.class,
+ return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + getQuery(getConfig(), parameters), TagFamilyResponse.class,
tagFamilyUpdateRequest);
}
@@ -571,10 +570,10 @@ public MeshRequest createGroup(String uuid, GroupCreateRequest gr
}
@Override
- public MeshRequest updateGroup(String uuid, GroupUpdateRequest groupUpdateRequest) {
+ public MeshRequest updateGroup(String uuid, GroupUpdateRequest groupUpdateRequest, ParameterProvider... parameters) {
Util.requireUuid(uuid, "uuid");
Objects.requireNonNull(groupUpdateRequest, "groupUpdateRequest must not be null");
- return prepareRequest(POST, "/groups/" + uuid, GroupResponse.class, groupUpdateRequest);
+ return prepareRequest(POST, "/groups/" + uuid + getQuery(getConfig(), parameters), GroupResponse.class, groupUpdateRequest);
}
@Override
@@ -807,10 +806,10 @@ public MeshRequest createSchema(String uuid, SchemaCreateRequest
}
@Override
- public MeshRequest updateRole(String uuid, RoleUpdateRequest restRole) {
+ public MeshRequest updateRole(String uuid, RoleUpdateRequest restRole, ParameterProvider... parameters) {
Util.requireUuid(uuid, "uuid");
Objects.requireNonNull(restRole, "restRole must not be null");
- return prepareRequest(POST, "/roles/" + uuid, RoleResponse.class, restRole);
+ return prepareRequest(POST, "/roles/" + uuid + getQuery(getConfig(), parameters), RoleResponse.class, restRole);
}
@Override
@@ -984,9 +983,9 @@ public MeshRequest searchUsers(String json, ParameterProvider.
}
@Override
- public MeshRequest searchUsersRaw(String json) {
+ public MeshRequest searchUsersRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/users", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/users" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -996,9 +995,9 @@ public MeshRequest searchGroups(String json, ParameterProvide
}
@Override
- public MeshRequest searchGroupsRaw(String json) {
+ public MeshRequest searchGroupsRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/groups", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/groups" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1008,9 +1007,9 @@ public MeshRequest searchRoles(String json, ParameterProvider.
}
@Override
- public MeshRequest searchRolesRaw(String json) {
+ public MeshRequest searchRolesRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/roles", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/roles" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1020,9 +1019,9 @@ public MeshRequest searchMicroschemas(String json, Para
}
@Override
- public MeshRequest searchMicroschemasRaw(String json) {
+ public MeshRequest searchMicroschemasRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/microschemas", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/microschemas" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1032,9 +1031,9 @@ public MeshRequest searchProjects(String json, ParameterPro
}
@Override
- public MeshRequest searchProjectsRaw(String json) {
+ public MeshRequest searchProjectsRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/projects", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/projects" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1044,9 +1043,9 @@ public MeshRequest searchTags(String json, ParameterProvider...
}
@Override
- public MeshRequest searchTagsRaw(String json) {
+ public MeshRequest searchTagsRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/tags", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/tags" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1057,10 +1056,10 @@ public MeshRequest searchTags(String projectName, String json,
}
@Override
- public MeshRequest searchTagsRaw(String projectName, String json) {
+ public MeshRequest searchTagsRaw(String projectName, String json, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/" + encodeSegment(projectName) + "/rawSearch/tags", ObjectNode.class, json);
+ return handleRequest(POST, "/" + encodeSegment(projectName) + "/rawSearch/tags" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1070,9 +1069,9 @@ public MeshRequest searchSchemas(String json, ParameterProvi
}
@Override
- public MeshRequest searchSchemasRaw(String json) {
+ public MeshRequest searchSchemasRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/schemas", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/schemas" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1082,9 +1081,9 @@ public MeshRequest searchTagFamilies(String json, Paramet
}
@Override
- public MeshRequest searchTagFamiliesRaw(String json) {
+ public MeshRequest searchTagFamiliesRaw(String json, ParameterProvider... parameters) {
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/rawSearch/tagFamilies", ObjectNode.class, json);
+ return handleRequest(POST, "/rawSearch/tagFamilies" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1096,10 +1095,10 @@ public MeshRequest searchTagFamilies(String projectName,
}
@Override
- public MeshRequest searchTagFamiliesRaw(String projectName, String json) {
+ public MeshRequest searchTagFamiliesRaw(String projectName, String json, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Objects.requireNonNull(json, "json must not be null");
- return handleRequest(POST, "/" + encodeSegment(projectName) + "/rawSearch/tagFamilies", ObjectNode.class, json);
+ return handleRequest(POST, "/" + encodeSegment(projectName) + "/rawSearch/tagFamilies" + getQuery(getConfig(), parameters), ObjectNode.class, json);
}
@Override
@@ -1117,31 +1116,6 @@ public MeshRequest searchStatus() {
return prepareRequest(GET, "/search/status", SearchStatusResponse.class);
}
- @Override
- public MeshRequest invokeBackup() {
- return prepareRequest(POST, "/admin/graphdb/backup", GenericMessageResponse.class);
- }
-
- @Override
- public MeshRequest invokeBackup(BackupParameters parameters) {
- return prepareRequest(POST, "/admin/graphdb/backup" + getQuery(getConfig(), parameters), GenericMessageResponse.class);
- }
-
- @Override
- public MeshRequest invokeExport() {
- return prepareRequest(POST, "/admin/graphdb/export", GenericMessageResponse.class);
- }
-
- @Override
- public MeshRequest invokeImport() {
- return prepareRequest(POST, "/admin/graphdb/import", GenericMessageResponse.class);
- }
-
- @Override
- public MeshRequest invokeRestore() {
- return prepareRequest(POST, "/admin/graphdb/restore", GenericMessageResponse.class);
- }
-
@Override
public MeshRequest checkConsistency(ParameterProvider... parameters) {
return prepareRequest(GET, "/admin/consistency/check" + getQuery(getConfig(), parameters), ConsistencyCheckResponse.class);
@@ -1223,18 +1197,13 @@ public MeshRequest downloadBinaryField(String projectName, S
@Override
public MeshRequest downloadBinaryField(String projectName, String nodeUuid, String languageTag, String fieldKey, long from,
long to, ParameterProvider... parameters) {
- Objects.requireNonNull(projectName, "projectName must not be null");
- Util.requireUuid(nodeUuid, "nodeUuid");
- Objects.requireNonNull(fieldKey, "fieldKey must not be null");
Util.requireNonNegative(from, "from");
Util.requireNonNegative(to, "to");
if (to < from) {
throw new InvalidParameterException(String.format("Parameter to must be equal or greater then from. Given values: %d-%d", from, to));
}
- String path = "/" + encodeSegment(projectName) + "/nodes/" + nodeUuid + "/binary/" + encodeSegment(fieldKey) + getQuery(getConfig(), parameters);
-
- MeshRequest request = prepareRequest(GET, path, MeshBinaryResponse.class);
+ MeshRequest request = downloadBinaryField(projectName, nodeUuid, languageTag, fieldKey, parameters);
request.setHeader("Range", String.format("bytes=%d-%d", from, to));
return request;
}
@@ -1402,11 +1371,11 @@ public MeshRequest findBranches(String projectName, Paramete
}
@Override
- public MeshRequest updateBranch(String projectName, String branchUuid, BranchUpdateRequest request) {
+ public MeshRequest updateBranch(String projectName, String branchUuid, BranchUpdateRequest request, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Util.requireUuid(branchUuid, "branchUuid");
- return prepareRequest(POST, "/" + encodeSegment(projectName) + "/branches/" + branchUuid, BranchResponse.class, request);
+ return prepareRequest(POST, "/" + encodeSegment(projectName) + "/branches/" + branchUuid + getQuery(getConfig(), parameters), BranchResponse.class, request);
}
@Override
@@ -1422,11 +1391,18 @@ public MeshRequest getRAML() {
}
@Override
- public MeshRequest getBranchSchemaVersions(String projectName, String branchUuid) {
+ public MeshRequest getOpenAPI() {
+ MeshRequest request = prepareRequest(GET, "/openapi.yaml" + getQuery(getConfig()), String.class);
+ request.setHeader("Accept", "*/*");
+ return request;
+ }
+
+ @Override
+ public MeshRequest getBranchSchemaVersions(String projectName, String branchUuid, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Util.requireUuid(branchUuid, "branchUuid");
- return prepareRequest(GET, "/" + encodeSegment(projectName) + "/branches/" + branchUuid + "/schemas", BranchInfoSchemaList.class);
+ return prepareRequest(GET, "/" + encodeSegment(projectName) + "/branches/" + branchUuid + "/schemas" + getQuery(getConfig(), parameters), BranchInfoSchemaList.class);
}
@Override
@@ -1449,11 +1425,11 @@ public MeshRequest assignBranchSchemaVersions(String proje
}
@Override
- public MeshRequest getBranchMicroschemaVersions(String projectName, String branchUuid) {
+ public MeshRequest getBranchMicroschemaVersions(String projectName, String branchUuid, ParameterProvider... parameters) {
Objects.requireNonNull(projectName, "projectName must not be null");
Util.requireUuid(branchUuid, "branchUuid");
- return prepareRequest(GET, "/" + encodeSegment(projectName) + "/branches/" + branchUuid + "/microschemas",
+ return prepareRequest(GET, "/" + encodeSegment(projectName) + "/branches/" + branchUuid + "/microschemas" + getQuery(getConfig(), parameters),
BranchInfoMicroschemaList.class);
}
@@ -1921,9 +1897,9 @@ public MeshRequest revokeProjectRolePermissions(String
}
@Override
- public MeshRequest getRoleRolePermissions(String uuid) {
+ public MeshRequest getRoleRolePermissions(String uuid, ParameterProvider... parameters) {
Util.requireUuid(uuid, "uuid");
- return prepareRequest(GET, "/roles/" + uuid + "/rolePermissions", ObjectPermissionResponse.class);
+ return prepareRequest(GET, "/roles/" + uuid + "/rolePermissions" + getQuery(getConfig(), parameters), ObjectPermissionResponse.class);
}
@Override
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/OkHttpWebsocket.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/OkHttpWebsocket.java
index 00378f696b..5d3226cc8e 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/OkHttpWebsocket.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/OkHttpWebsocket.java
@@ -1,19 +1,33 @@
package com.gentics.mesh.rest.client.impl;
+import static com.gentics.mesh.rest.client.impl.Util.eventbusMessage;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.gentics.mesh.json.JsonUtil;
import com.gentics.mesh.rest.client.EventbusEvent;
import com.gentics.mesh.rest.client.MeshRestClientConfig;
import com.gentics.mesh.rest.client.MeshWebsocket;
+
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
@@ -21,19 +35,6 @@
import okhttp3.WebSocketListener;
import okio.ByteString;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Stream;
-
-import static com.gentics.mesh.rest.client.impl.Util.eventbusMessage;
-
/**
* Websocket client implementation for {@link OkHttpClient}.
*/
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/Util.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/Util.java
index 9bf123f7e6..4787ef5775 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/Util.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/Util.java
@@ -3,6 +3,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidParameterException;
+import java.util.concurrent.Callable;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -79,7 +80,7 @@ public static String eventbusMessage(EventbusMessageType type, String address, O
* @param
* @return
*/
- public static Supplier lazily(WrappedSupplier supplier) {
+ public static Supplier lazily(Callable supplier) {
return new Supplier() {
T value;
boolean supplied = false;
@@ -88,7 +89,7 @@ public static Supplier lazily(WrappedSupplier supplier) {
public synchronized T get() {
if (!supplied) {
try {
- value = supplier.get();
+ value = supplier.call();
supplied = true;
} catch (Exception e) {
throw new RuntimeException(e);
@@ -170,8 +171,4 @@ public static String normalizedPath(String path) throws URISyntaxException {
return Strings.CI.removeStart(normalizedURI, "http://host");
}
-
- interface WrappedSupplier {
- T get() throws Exception;
- }
}
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/AdminClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/AdminClientMethods.java
index 18fd0956f8..e219515282 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/AdminClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/AdminClientMethods.java
@@ -34,44 +34,6 @@ public interface AdminClientMethods {
@Deprecated
MeshRequest clusterStatus();
- /**
- * Invoke a graph database backup.
- *
- * @return
- */
- MeshRequest invokeBackup();
-
- /**
- * Invoke a graph database backup.
- * @return
- */
- MeshRequest invokeBackup(BackupParameters parameters);
-
- /**
- * Invoke a graph database export.
- *
- * @return
- * @deprecated Endpoint currently not supported
- */
- @Deprecated
- MeshRequest invokeExport();
-
- /**
- * Invoke a graph database restore.
- *
- * @return
- */
- MeshRequest invokeRestore();
-
- /**
- * Invoke a graph database import.
- *
- * @return
- * @deprecated Endpoint currently not supported
- */
- @Deprecated
- MeshRequest invokeImport();
-
/**
* Invoke a consistency check of the graph database.
*
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ApiInfoClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ApiInfoClientMethods.java
index 374e94cc4b..1b8dd4d790 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ApiInfoClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ApiInfoClientMethods.java
@@ -24,4 +24,11 @@ public interface ApiInfoClientMethods {
* @return
*/
MeshRequest getRAML();
+
+ /**
+ * Generate an OpenAPI specification
+ *
+ * @return
+ */
+ MeshRequest getOpenAPI();
}
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java
index 46906da38a..7fc34484ec 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java
@@ -72,7 +72,7 @@ MeshRequest createBranch(String projectName, String uuid, Branch
* @param request
* @return
*/
- MeshRequest updateBranch(String projectName, String branchUuid, BranchUpdateRequest request);
+ MeshRequest updateBranch(String projectName, String branchUuid, BranchUpdateRequest request, ParameterProvider... parameters);
/**
* Get schema versions assigned to a branch.
@@ -81,7 +81,7 @@ MeshRequest createBranch(String projectName, String uuid, Branch
* @param branchUuid
* @return
*/
- MeshRequest getBranchSchemaVersions(String projectName, String branchUuid);
+ MeshRequest getBranchSchemaVersions(String projectName, String branchUuid, ParameterProvider... parameters);
/**
* Assign the given schema versions to the branch.
@@ -110,7 +110,7 @@ MeshRequest createBranch(String projectName, String uuid, Branch
* @param branchUuid
* @return
*/
- MeshRequest getBranchMicroschemaVersions(String projectName, String branchUuid);
+ MeshRequest getBranchMicroschemaVersions(String projectName, String branchUuid, ParameterProvider... parameters);
/**
* Assign the given microschema versions to the branch.
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java
index fdae5c62e7..090f0b6452 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java
@@ -57,7 +57,7 @@ public interface GroupClientMethods {
* @param request
* @return
*/
- MeshRequest updateGroup(String uuid, GroupUpdateRequest request);
+ MeshRequest updateGroup(String uuid, GroupUpdateRequest request, ParameterProvider... parameters);
/**
* Delete the group.
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java
index 9277f4f9a2..96c307e2ec 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java
@@ -51,7 +51,7 @@ public interface ProjectClientMethods {
* @param languageUuid
* @return
*/
- MeshRequest assignLanguageToProject(String projectUuid, String languageUuid);
+ MeshRequest assignLanguageToProject(String projectUuid, String languageUuid, ParameterProvider... parameters);
/**
* Unassign the given language from the project.
@@ -60,7 +60,7 @@ public interface ProjectClientMethods {
* @param languageUuid
* @return
*/
- MeshRequest unassignLanguageFromProject(String projectUuid, String languageUuid);
+ MeshRequest unassignLanguageFromProject(String projectUuid, String languageUuid, ParameterProvider... parameters);
/**
* Create a new project.
@@ -88,7 +88,7 @@ public interface ProjectClientMethods {
* @param request
* @return
*/
- MeshRequest updateProject(String uuid, ProjectUpdateRequest request);
+ MeshRequest updateProject(String uuid, ProjectUpdateRequest request, ParameterProvider... parameters);
/**
* Delete the project.
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java
index b65478a8ad..938cf0d3ad 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java
@@ -101,7 +101,7 @@ public interface RoleClientMethods {
* @param restRole
* @return
*/
- MeshRequest updateRole(String uuid, RoleUpdateRequest restRole);
+ MeshRequest updateRole(String uuid, RoleUpdateRequest restRole, ParameterProvider... parameters);
/**
* Get the role permissions on the role
@@ -110,7 +110,7 @@ public interface RoleClientMethods {
* Uuid of the role
* @return request
*/
- MeshRequest getRoleRolePermissions(String uuid);
+ MeshRequest getRoleRolePermissions(String uuid, ParameterProvider... parameters);
/**
* Grant permissions on the role to roles
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SearchClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SearchClientMethods.java
index a227bc9ce3..3b27ce16a5 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SearchClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SearchClientMethods.java
@@ -77,7 +77,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchUsersRaw(String json);
+ MeshRequest searchUsersRaw(String json, ParameterProvider... parameters);
/**
* Search groups.
@@ -95,7 +95,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchGroupsRaw(String json);
+ MeshRequest searchGroupsRaw(String json, ParameterProvider... parameters);
/**
* Search roles.
@@ -113,7 +113,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchRolesRaw(String json);
+ MeshRequest searchRolesRaw(String json, ParameterProvider... parameters);
/**
* Search projects.
@@ -131,7 +131,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchProjectsRaw(String json);
+ MeshRequest searchProjectsRaw(String json, ParameterProvider... parameters);
/**
* Search tags.
@@ -149,7 +149,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchTagsRaw(String json);
+ MeshRequest searchTagsRaw(String json, ParameterProvider... parameters);
/**
* Search tags in project
@@ -170,7 +170,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchTagsRaw(String projectName, String json);
+ MeshRequest searchTagsRaw(String projectName, String json, ParameterProvider... parameters);
/**
* Search tag families.
@@ -187,7 +187,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchTagFamiliesRaw(String json);
+ MeshRequest searchTagFamiliesRaw(String json, ParameterProvider... parameters);
/**
* Search tag families in project.
@@ -206,7 +206,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchTagFamiliesRaw(String projectName, String json);
+ MeshRequest searchTagFamiliesRaw(String projectName, String json, ParameterProvider... parameters);
/**
* Search schemas.
@@ -224,7 +224,7 @@ public interface SearchClientMethods {
* @param json
* @return
*/
- MeshRequest searchSchemasRaw(String json);
+ MeshRequest searchSchemasRaw(String json, ParameterProvider... parameters);
/**
* Search microschemas.
@@ -243,7 +243,7 @@ public interface SearchClientMethods {
* Elasticsearch search request
* @return
*/
- MeshRequest searchMicroschemasRaw(String json);
+ MeshRequest searchMicroschemasRaw(String json, ParameterProvider... parameters);
/**
* Clear all search indices by removing and re-creating them.
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java
index f57da8ba48..5174b57336 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java
@@ -53,7 +53,7 @@ public interface TagClientMethods {
* Update request
* @return
*/
- MeshRequest updateTag(String projectName, String tagFamilyUuid, String uuid, TagUpdateRequest request);
+ MeshRequest updateTag(String projectName, String tagFamilyUuid, String uuid, TagUpdateRequest request, ParameterProvider... parameters);
/**
* Create the tag with the given uuid
diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java
index bf6e9d3bfa..3ca322fd52 100644
--- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java
+++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java
@@ -70,7 +70,7 @@ public interface TagFamilyClientMethods {
* Update request
* @return
*/
- MeshRequest updateTagFamily(String projectName, String tagFamilyUuid, TagFamilyUpdateRequest request);
+ MeshRequest updateTagFamily(String projectName, String tagFamilyUuid, TagFamilyUpdateRequest request, ParameterProvider... parameters);
/**
* Create the tag family with the given uuid.
diff --git a/rest-model/pom.xml b/rest-model/pom.xml
index f60789fc2f..d826722cd7 100644
--- a/rest-model/pom.xml
+++ b/rest-model/pom.xml
@@ -34,31 +34,9 @@
com.gentics.mesh
mesh-api
-
-
- com.fasterxml.jackson.core
- jackson-annotations
-
-
- com.google.guava
- guava
-
-
- com.fasterxml.jackson.module
- jackson-module-jsonSchema
-
-
- org.codehaus.jettison
- jettison
- 1.5.4
-
-
- commons-io
- commons-io
-
- org.raml
- raml-parser
+ com.gentics
+ vertx-openapi
org.slf4j
@@ -86,6 +64,27 @@
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.google.guava
+ guava
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+
+
+ org.codehaus.jettison
+ jettison
+ 1.5.4
+
+
+ commons-io
+ commons-io
+
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/admin/localconfig/LocalConfigModel.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/admin/localconfig/LocalConfigModel.java
index 051a86b3fc..75620e5d83 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/admin/localconfig/LocalConfigModel.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/admin/localconfig/LocalConfigModel.java
@@ -12,6 +12,8 @@
*/
public class LocalConfigModel implements RestModel, Serializable {
+ private static final long serialVersionUID = 7018419343844051338L;
+
@JsonProperty
@JsonPropertyDescription("If true, mutating requests to this instance are not allowed.")
private Boolean readOnly = false;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/auth/TokenResponse.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/auth/TokenResponse.java
index 64ba7d72d9..3e057f67dc 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/auth/TokenResponse.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/auth/TokenResponse.java
@@ -1,11 +1,16 @@
package com.gentics.mesh.core.rest.auth;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.gentics.mesh.core.rest.common.RestModel;
/**
* This response is returned when a new JWToken is requested.
*/
public class TokenResponse implements RestModel {
+
+ @JsonProperty(required = false)
+ @JsonPropertyDescription("A current JWT access token")
private String token;
public String getToken() {
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/GenericMessageResponse.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/GenericMessageResponse.java
index 9692005e64..04cb493aa6 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/GenericMessageResponse.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/GenericMessageResponse.java
@@ -4,17 +4,14 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import com.gentics.vertx.openapi.model.MessageResponse;
/**
* The {@link GenericMessageResponse} is used when a generic message should be returned to the requester.
*/
-public class GenericMessageResponse implements RestModel {
+public class GenericMessageResponse extends MessageResponse implements RestModel {
- @JsonProperty(required = true)
- @JsonPropertyDescription("Enduser friendly translated message. Translation depends on the 'Accept-Language' header value")
- private String message;
-
- @JsonProperty(required = true)
+ @JsonProperty(required = false)
@JsonPropertyDescription("Internal developer friendly message")
private String internalMessage;
@@ -26,6 +23,7 @@ public class GenericMessageResponse implements RestModel {
* Create a new generic message response POJO.
*/
public GenericMessageResponse() {
+ super();
}
/**
@@ -47,29 +45,10 @@ public GenericMessageResponse(String message) {
* Internal message which may describe the message in a more technical fashion
*/
public GenericMessageResponse(String message, String internalMessage) {
- this.message = message;
+ super(message);
this.internalMessage = internalMessage;
}
- /**
- * Return the message string.
- *
- * @return Message
- */
- public String getMessage() {
- return message;
- }
-
- /**
- * Set the message string.
- *
- * @param message
- * Message
- */
- public void setMessage(String message) {
- this.message = message;
- }
-
/**
* Return the internal message.
*
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/NameUuidReference.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/NameUuidReference.java
index d36d462926..9f0a22ef3e 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/NameUuidReference.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/NameUuidReference.java
@@ -5,7 +5,7 @@
*
* @param
*/
-public interface NameUuidReference {
+public interface NameUuidReference extends RestModel {
/**
* Return the name of the referenced element.
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/PagingMetaInfo.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/PagingMetaInfo.java
index cfebe14491..abb891e423 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/PagingMetaInfo.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/PagingMetaInfo.java
@@ -6,13 +6,13 @@
/**
* Paging meta info model.
*/
-public class PagingMetaInfo {
+public class PagingMetaInfo implements RestModel {
@JsonProperty(required = true)
@JsonPropertyDescription("Number of the current page.")
private long currentPage;
- @JsonProperty(required = true)
+ @JsonProperty(required = false)
@JsonPropertyDescription("Number of elements which can be included in a single page.")
private Long perPage;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/RestModel.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/RestModel.java
index b1a89fa6c9..ee432ede4a 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/RestModel.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/RestModel.java
@@ -9,22 +9,8 @@
* Marker interface for all rest models.
*/
@GenerateDocumentation
-public interface RestModel extends Shareable {
+public interface RestModel extends com.gentics.vertx.openapi.model.RestModel, Shareable {
- /**
- * Transforms the model into a JSON string, with pretty formatting.
- *
- * @return
- */
- default String toJson() {
- return toJson(true);
- }
-
- /**
- * Transforms the model into a JSON string.
- *
- * @return
- */
default String toJson(boolean minify) {
return JsonUtil.toJson(this, minify);
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/job/JobResponse.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/job/JobResponse.java
index 668c05fa92..765fbf9ffa 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/job/JobResponse.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/job/JobResponse.java
@@ -16,7 +16,7 @@
*/
public class JobResponse extends AbstractResponse {
- @JsonProperty(required = true)
+ @JsonProperty(required = false)
@JsonPropertyDescription("User reference of the creator of the element.")
private UserReference creator;
@@ -44,11 +44,11 @@ public class JobResponse extends AbstractResponse {
@JsonPropertyDescription("Properties of the job.")
private Map properties = new HashMap<>();
- @JsonProperty(required = true)
+ @JsonProperty(required = false)
@JsonPropertyDescription("The stop date of the job.")
private String stopDate;
- @JsonProperty(required = true)
+ @JsonProperty(required = false)
@JsonPropertyDescription("The start date of the job.")
private String startDate;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/navigation/NavigationElement.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/navigation/NavigationElement.java
index 919821822a..00326b25c5 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/navigation/NavigationElement.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/navigation/NavigationElement.java
@@ -3,12 +3,13 @@
import java.util.List;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import com.gentics.mesh.core.rest.common.RestModel;
import com.gentics.mesh.core.rest.node.NodeResponse;
/**
* A navigation element is a reference to a node within the navigation tree.
*/
-public class NavigationElement {
+public class NavigationElement implements RestModel {
@JsonPropertyDescription("Uuid of the node within this navigation element.")
private String uuid;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/node/field/NodeFieldListItem.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/node/field/NodeFieldListItem.java
index 77b483b70c..379d078e8b 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/node/field/NodeFieldListItem.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/node/field/NodeFieldListItem.java
@@ -1,9 +1,11 @@
package com.gentics.mesh.core.rest.node.field;
+import com.gentics.mesh.core.rest.common.RestModel;
+
/**
* Entry for a node list REST model.
*/
-public interface NodeFieldListItem {
+public interface NodeFieldListItem extends RestModel {
/**
* Return the item node uuid.
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/BinaryExtractOptions.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/BinaryExtractOptions.java
index c746219e8f..1b8d1dddc8 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/BinaryExtractOptions.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/BinaryExtractOptions.java
@@ -1,9 +1,11 @@
package com.gentics.mesh.core.rest.schema;
+import com.gentics.mesh.core.rest.common.RestModel;
+
/**
* Determines what parts of the binary data should be extracted and sent to Elasticsearch.
*/
-public class BinaryExtractOptions {
+public class BinaryExtractOptions implements RestModel {
private boolean content;
private boolean metadata;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchema.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchema.java
index b9d8465622..4ad1db7474 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchema.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchema.java
@@ -6,6 +6,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import com.gentics.mesh.core.rest.common.RestModel;
import com.gentics.mesh.core.rest.schema.change.impl.SchemaChangeModel;
import com.gentics.mesh.etc.config.search.ElasticSearchOptions;
import com.gentics.mesh.etc.config.search.MappingMode;
@@ -16,7 +17,7 @@
* A field schema is a field within a schema. In contradiction to node fields a field schema is the blueprint of a field and will not store any data. Instead it
* only defines a field within a schema.
*/
-public interface FieldSchema {
+public interface FieldSchema extends RestModel {
/**
* Return the type of the field schema.
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/S3BinaryExtractOptions.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/S3BinaryExtractOptions.java
index ef8919272a..5f4b4928b7 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/S3BinaryExtractOptions.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/S3BinaryExtractOptions.java
@@ -1,9 +1,11 @@
package com.gentics.mesh.core.rest.schema;
+import com.gentics.mesh.core.rest.common.RestModel;
+
/**
* Determines what parts of the s3binary data should be extracted and sent to Elasticsearch.
*/
-public class S3BinaryExtractOptions {
+public class S3BinaryExtractOptions implements RestModel {
private boolean content;
private boolean metadata;
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/user/ExpandableNode.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/user/ExpandableNode.java
index 4c1d37b03c..3386e7755b 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/user/ExpandableNode.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/user/ExpandableNode.java
@@ -1,9 +1,11 @@
package com.gentics.mesh.core.rest.user;
+import com.gentics.mesh.core.rest.common.RestModel;
+
/**
* Marker interface which is used to identify a node field which can be expanded.
*/
-public interface ExpandableNode {
+public interface ExpandableNode extends RestModel {
/**
* Return the node uuid.
diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/user/NodeReference.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/user/NodeReference.java
index c6e70c5558..1878ecee2c 100644
--- a/rest-model/src/main/java/com/gentics/mesh/core/rest/user/NodeReference.java
+++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/user/NodeReference.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.gentics.mesh.core.rest.common.RestModel;
import com.gentics.mesh.core.rest.node.NodeResponse;
import com.gentics.mesh.core.rest.schema.SchemaReference;
import com.gentics.mesh.core.rest.schema.impl.SchemaReferenceImpl;
@@ -12,7 +13,7 @@
* A node reference contains the bare minimum of useful information which identifies a node. Various field in the {@link NodeResponse} utilize these references
* in order to reduce data.
*/
-public class NodeReference implements ExpandableNode {
+public class NodeReference implements ExpandableNode, RestModel {
@JsonProperty(required = true)
@JsonPropertyDescription("Name of the project to which the node belongs")
diff --git a/rest-model/src/main/java/com/gentics/mesh/json/JsonUtil.java b/rest-model/src/main/java/com/gentics/mesh/json/JsonUtil.java
index 9b495f6ab5..65be61a627 100644
--- a/rest-model/src/main/java/com/gentics/mesh/json/JsonUtil.java
+++ b/rest-model/src/main/java/com/gentics/mesh/json/JsonUtil.java
@@ -6,6 +6,8 @@
import java.io.IOException;
import org.codehaus.jettison.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -19,11 +21,14 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import com.gentics.mesh.core.rest.error.AbstractRestException;
import com.gentics.mesh.core.rest.error.GenericRestException;
@@ -53,21 +58,19 @@
import com.gentics.mesh.json.deserializer.FieldDeserializer;
import com.gentics.mesh.json.deserializer.FieldMapDeserializer;
import com.gentics.mesh.json.deserializer.FieldSchemaDeserializer;
-import com.gentics.mesh.json.deserializer.JsonArrayDeserializer;
-import com.gentics.mesh.json.deserializer.JsonObjectDeserializer;
import com.gentics.mesh.json.deserializer.NodeFieldListItemDeserializer;
import com.gentics.mesh.json.deserializer.PermissionChangedEventModelDeserializer;
import com.gentics.mesh.json.deserializer.RestExceptionDeserializer;
import com.gentics.mesh.json.deserializer.UserNodeReferenceDeserializer;
import com.gentics.mesh.json.serializer.BasicFieldSerializer;
import com.gentics.mesh.json.serializer.FieldListSerializer;
-import com.gentics.mesh.json.serializer.JsonArraySerializer;
-import com.gentics.mesh.json.serializer.JsonObjectSerializer;
+import com.gentics.vertx.openapi.model.serde.JsonArrayDeserializer;
+import com.gentics.vertx.openapi.model.serde.JsonArraySerializer;
+import com.gentics.vertx.openapi.model.serde.JsonObjectDeserializer;
+import com.gentics.vertx.openapi.model.serde.JsonObjectSerializer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Main JSON Util which is used to register all custom JSON specific handlers and deserializers.
@@ -91,8 +94,11 @@ public final class JsonUtil {
private static void initDefaultMapper() {
minifyingPrettyPrinter = new MinimalPrettyPrinter();
- defaultMapper = new ObjectMapper(new JsonFactoryBuilder()
- .streamReadConstraints(StreamReadConstraints.builder().maxStringLength(Integer.MAX_VALUE).build()).build());
+ defaultMapper = JsonMapper.builder(new JsonFactoryBuilder()
+ .streamReadConstraints(StreamReadConstraints.builder().maxStringLength(Integer.MAX_VALUE).build())
+ .build())
+ .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
+ .build();
defaultMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(Include.NON_NULL, Include.ALWAYS));
defaultMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -238,21 +244,46 @@ public static T readValue(String content, Class valueType) throws Generic
}
/**
- * Generate the JSON schema for the given model class.
+ * Generate the JSON string for the given model schema.
*
* @param clazz
* Model class
* @return
*/
- public static String getJsonSchema(Class> clazz) {
+ public static String getJsonSchema(JsonSchema schema) {
try {
- com.fasterxml.jackson.module.jsonSchema.JsonSchema schema = schemaGen.generateSchema(clazz);
return defaultMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
} catch (Exception e) {
throw new GenericRestException(INTERNAL_SERVER_ERROR, "error_internal", e);
}
}
+ /**
+ * Generate the JSON schema model for the given model class.
+ *
+ * @param clazz
+ * Model class
+ * @return
+ */
+ public static String getJsonSchema(Class> clazz) {
+ return getJsonSchema(getJsonSchemaObject(clazz));
+ }
+
+ /**
+ * Generate the JSON schema for the given model class.
+ *
+ * @param clazz
+ * Model class
+ * @return
+ */
+ public static JsonSchema getJsonSchemaObject(Class> clazz) {
+ try {
+ return schemaGen.generateSchema(clazz);
+ } catch (Exception e) {
+ throw new GenericRestException(INTERNAL_SERVER_ERROR, "error_internal", e);
+ }
+ }
+
/**
* Return the JSON object mapper.
*
diff --git a/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonArrayDeserializer.java b/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonArrayDeserializer.java
deleted file mode 100644
index 0d852818f3..0000000000
--- a/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonArrayDeserializer.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.gentics.mesh.json.deserializer;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import io.vertx.core.json.JsonArray;
-
-/**
- * Custom deserializer for Vert.x {@link JsonArray}
- */
-public class JsonArrayDeserializer extends JsonDeserializer {
-
- @Override
- public JsonArray deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
- ObjectCodec oc = jsonParser.getCodec();
- JsonNode node = oc.readTree(jsonParser);
- return new JsonArray(node.toString());
- }
-
-}
diff --git a/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonObjectDeserializer.java b/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonObjectDeserializer.java
deleted file mode 100644
index b0b09e10ef..0000000000
--- a/rest-model/src/main/java/com/gentics/mesh/json/deserializer/JsonObjectDeserializer.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.gentics.mesh.json.deserializer;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import io.vertx.core.json.JsonObject;
-
-/**
- * Custom deserializer for {@link JsonObject}
- */
-public class JsonObjectDeserializer extends JsonDeserializer {
-
- @Override
- public JsonObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
- ObjectCodec oc = jsonParser.getCodec();
- JsonNode node = oc.readTree(jsonParser);
- return new JsonObject(node.toString());
- }
-
-}
diff --git a/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonArraySerializer.java b/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonArraySerializer.java
deleted file mode 100644
index d7647e3515..0000000000
--- a/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonArraySerializer.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.gentics.mesh.json.serializer;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import io.vertx.core.json.JsonArray;
-
-/**
- * Custom JSON serializer for Vert.x {@link JsonArray}.
- */
-public class JsonArraySerializer extends JsonSerializer {
-
- @Override
- public void serialize(JsonArray value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
- jgen.writeObject(value.getList());
- }
-}
diff --git a/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonObjectSerializer.java b/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonObjectSerializer.java
deleted file mode 100644
index e6824245fe..0000000000
--- a/rest-model/src/main/java/com/gentics/mesh/json/serializer/JsonObjectSerializer.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.gentics.mesh.json.serializer;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import io.vertx.core.json.JsonObject;
-
-/**
- * Custom serializer for Vert.x {@link JsonObject}
- */
-public class JsonObjectSerializer extends JsonSerializer {
-
- @Override
- public void serialize(JsonObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
- jgen.writeObject(value.getMap());
- }
-}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/BackupParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/BackupParameters.java
index d94d292628..f9b144f295 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/BackupParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/BackupParameters.java
@@ -26,6 +26,6 @@ default BackupParameters setConsistencyCheck(boolean flag) {
* @return
*/
default boolean isConsistencyCheck() {
- return BooleanUtils.toBooleanDefaultIfNull(Boolean.valueOf(getParameter(CONSISTENCY_CHECK_PARAMETER_KEY)), false);
+ return BooleanUtils.toBooleanDefaultIfNull(BooleanUtils.toBooleanObject(getParameter(CONSISTENCY_CHECK_PARAMETER_KEY)), false);
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/ConsistencyCheckParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/ConsistencyCheckParameters.java
index 09864656b6..a9e0d2b902 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/ConsistencyCheckParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/ConsistencyCheckParameters.java
@@ -28,6 +28,6 @@ default ConsistencyCheckParameters setAsync(boolean flag) {
* @return flag value
*/
default boolean isAsync() {
- return BooleanUtils.toBooleanDefaultIfNull(Boolean.valueOf(getParameter(ASYNC_PARAMETER_KEY)), false);
+ return BooleanUtils.toBooleanDefaultIfNull(BooleanUtils.toBooleanObject(getParameter(ASYNC_PARAMETER_KEY)), false);
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/DeleteParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/DeleteParameters.java
index 6efbde63c7..b5e4a23609 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/DeleteParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/DeleteParameters.java
@@ -26,6 +26,6 @@ default DeleteParameters setRecursive(boolean flag) {
* @return
*/
default boolean isRecursive() {
- return BooleanUtils.toBooleanDefaultIfNull(Boolean.valueOf(getParameter(RECURSIVE_PARAMETER_KEY)), false);
+ return BooleanUtils.toBooleanDefaultIfNull(BooleanUtils.toBooleanObject(getParameter(RECURSIVE_PARAMETER_KEY)), false);
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/EtagParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/EtagParameters.java
new file mode 100644
index 0000000000..b73c457940
--- /dev/null
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/EtagParameters.java
@@ -0,0 +1,36 @@
+package com.gentics.mesh.parameter;
+
+/**
+ * ETAG parameters
+ */
+public interface EtagParameters extends ParameterProvider {
+
+ /**
+ * Query parameter key: {@value #ETAG_PARAM_KEY}
+ */
+ public static final String ETAG_PARAM_KEY = "etag";
+
+ /**
+ * Return whether the etag should be omitted or included.
+ *
+ * @return
+ */
+ default boolean getETag() {
+ String value = getParameter(ETAG_PARAM_KEY);
+ if (value != null) {
+ return Boolean.valueOf(value);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Set the etag inclusion flag.
+ *
+ * @param includeEtag
+ */
+ default EtagParameters setETag(boolean includeEtag) {
+ setParameter(ETAG_PARAM_KEY, String.valueOf(includeEtag));
+ return this;
+ }
+}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/GenericParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/GenericParameters.java
index a7ca8afa60..a926091f17 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/GenericParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/GenericParameters.java
@@ -6,18 +6,13 @@
/**
* Interface for generic query parameters.
*/
-public interface GenericParameters extends ParameterProvider {
+public interface GenericParameters extends EtagParameters {
/**
* Query parameter key: {@value #FIELDS_PARAM_KEY}
*/
public static final String FIELDS_PARAM_KEY = "fields";
- /**
- * Query parameter key: {@value #ETAG_PARAM_KEY}
- */
- public static final String ETAG_PARAM_KEY = "etag";
-
/**
* Return the fields which should be included in the response.
*
@@ -43,27 +38,9 @@ default GenericParameters setFields(String... fields) {
return this;
}
- /**
- * Return whether the etag should be omitted or included.
- *
- * @return
- */
- default boolean getETag() {
- String value = getParameter(ETAG_PARAM_KEY);
- if (value != null) {
- return Boolean.valueOf(value);
- } else {
- return true;
- }
- }
-
- /**
- * Set the etag inclusion flag.
- *
- * @param includeEtag
- */
+ @Override
default GenericParameters setETag(boolean includeEtag) {
- setParameter(ETAG_PARAM_KEY, String.valueOf(includeEtag));
+ EtagParameters.super.setETag(includeEtag);
return this;
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/LanguageParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/LanguageParameters.java
new file mode 100644
index 0000000000..cfa34f543c
--- /dev/null
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/LanguageParameters.java
@@ -0,0 +1,38 @@
+package com.gentics.mesh.parameter;
+
+/**
+ * Language parameters
+ */
+public interface LanguageParameters extends ParameterProvider {
+
+ /**
+ * Query parameter key: {@value #LANGUAGES_QUERY_PARAM_KEY}
+ */
+ public static final String LANGUAGES_QUERY_PARAM_KEY = "lang";
+
+
+ /**
+ * Set the {@value #LANGUAGES_QUERY_PARAM_KEY} request parameter values.
+ *
+ * @param languageTags
+ * @return Fluent API
+ */
+ default LanguageParameters setLanguages(String... languageTags) {
+ setParameter(LANGUAGES_QUERY_PARAM_KEY, convertToStr(languageTags));
+ return this;
+ }
+
+ /**
+ * Return the {@value #LANGUAGES_QUERY_PARAM_KEY} request parameter values.
+ *
+ * @return
+ */
+ default String[] getLanguages() {
+ String value = getParameter(LANGUAGES_QUERY_PARAM_KEY);
+ String[] languages = null;
+ if (value != null) {
+ languages = value.split(",");
+ }
+ return languages;
+ }
+}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/NodeParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/NodeParameters.java
index 30ee7fba14..0b32dec895 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/NodeParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/NodeParameters.java
@@ -8,12 +8,7 @@
/**
* Interface for node query parameters.
*/
-public interface NodeParameters extends ParameterProvider {
-
- /**
- * Query parameter key: {@value #LANGUAGES_QUERY_PARAM_KEY}
- */
- public static final String LANGUAGES_QUERY_PARAM_KEY = "lang";
+public interface NodeParameters extends LanguageParameters {
/**
* Query parameter key: {@value #EXPANDFIELDS_QUERY_PARAM_KEY}
@@ -36,25 +31,12 @@ public interface NodeParameters extends ParameterProvider {
* @param languageTags
* @return Fluent API
*/
+ @Override
default NodeParameters setLanguages(String... languageTags) {
- setParameter(LANGUAGES_QUERY_PARAM_KEY, convertToStr(languageTags));
+ LanguageParameters.super.setLanguages(languageTags);
return this;
}
- /**
- * Return the {@value #LANGUAGES_QUERY_PARAM_KEY} request parameter values.
- *
- * @return
- */
- default String[] getLanguages() {
- String value = getParameter(LANGUAGES_QUERY_PARAM_KEY);
- String[] languages = null;
- if (value != null) {
- languages = value.split(",");
- }
- return languages;
- }
-
/**
* Set the {@value #RESOLVE_LINKS_QUERY_PARAM_KEY} request parameter.
*
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/ParameterProvider.java b/rest-model/src/main/java/com/gentics/mesh/parameter/ParameterProvider.java
index ab08130ff8..3d878ae7c0 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/ParameterProvider.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/ParameterProvider.java
@@ -1,157 +1,8 @@
package com.gentics.mesh.parameter;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang.BooleanUtils;
-import org.raml.model.parameter.QueryParameter;
-
/**
* Common interface for query parameters.
*/
-public interface ParameterProvider {
-
- /**
- * * Validate the parameters and throw an exception when an invalid set of parameters has been detected.
- */
- default void validate() {
- }
-
- /**
- * Return the RAML parameters for this provider.
- *
- * @return
- */
- Map extends String, ? extends QueryParameter> getRAMLParameters();
-
- /**
- * Set the query parameter.
- *
- * @param name
- * Parameter name
- * @param value
- * Parameter value
- */
- void setParameter(String name, String value);
-
- /**
- * Set the multivalue query parameter
- * @param value type
- * @param name parameter name
- * @param values parameter values
- * @param converter function to convert the values into strings
- */
- default void setMultivalueParameter(String name, Collection values, Function converter) {
- if (values == null) {
- setParameter(name, null);
- } else {
- setParameter(name, values.stream().map(converter::apply).collect(Collectors.joining(",")));
- }
- }
-
- /**
- * Set the multivalue query parameter to string values
- * @param name name
- * @param values string values
- */
- default void setMultivalueParameter(String name, Collection values) {
- setMultivalueParameter(name, values, Function.identity());
- }
-
- /**
- * Return the query parameter value for the given name.
- *
- * @param name
- * Parameter name
- * @return Loaded value or null
- */
- String getParameter(String name);
-
- /**
- * Return the query parameter values for the given name.
- * @param value type
- * @param name parameter name
- * @param converter function that converts the stores String into the expected value
- * @return Loaded values or empty set
- */
- default Set getMultivalueParameter(String name, Function converter) {
- String value = getParameter(name);
- if (value == null || value.isEmpty()) {
- return Collections.emptySet();
- } else {
- return Arrays.asList(value.split(",")).stream().map(converter::apply).collect(Collectors.toSet());
- }
- }
-
- /**
- * Return the query parameter values for the given name as set of strings
- * @param name parameter name
- * @return Loaded values or empty set
- */
- default Set getMultivalueParameter(String name) {
- return getMultivalueParameter(name, Function.identity());
- }
-
- /**
- * Return the query parameters as a map.
- *
- * @return
- */
- Map getParameters();
-
- /**
- * Convert the provides object to a string representation.
- *
- * @param value
- * @return String representation of value
- */
- default String convertToStr(Object value) {
- if (value instanceof String[]) {
- String stringVal = "";
- String[] values = (String[]) value;
- for (int i = 0; i < values.length; i++) {
- stringVal += values[i];
- if (i != values.length - 1) {
- stringVal += ',';
- }
- }
- return stringVal;
- } else if (value instanceof Integer) {
- return Integer.toString((int) value);
- } else if (value instanceof Boolean) {
- return BooleanUtils.toStringTrueFalse((Boolean) value);
- } else {
- return value.toString();
- }
- }
-
- /**
- * Return the query parameters which do not include the the first & or ? character.
- *
- * @return Query string
- */
- default String getQueryParameters() {
- StringBuilder query = new StringBuilder();
- Map params = getParameters();
- for (Entry entry : params.entrySet()) {
- String value = entry.getValue();
- if (value != null) {
- if (query.length() != 0) {
- query.append("&");
- }
- // try {
- query.append(entry.getKey() + "=" + value);// URLEncoder.encode(value, "UTF-8"));
- // } catch (UnsupportedEncodingException e) {
- // }
- }
- }
- return query.toString();
- }
+public interface ParameterProvider extends com.gentics.vertx.openapi.model.ParameterProvider {
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/PublishParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/PublishParameters.java
index 7587d61098..c3aefc34b6 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/PublishParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/PublishParameters.java
@@ -27,7 +27,7 @@ default PublishParameters setRecursive(boolean flag) {
*/
default boolean isRecursive() {
- return BooleanUtils.toBooleanDefaultIfNull(Boolean.valueOf(getParameter(RECURSIVE_PARAMETER_KEY)), false);
+ return BooleanUtils.toBooleanDefaultIfNull(BooleanUtils.toBooleanObject(getParameter(RECURSIVE_PARAMETER_KEY)), false);
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/SchemaUpdateParameters.java b/rest-model/src/main/java/com/gentics/mesh/parameter/SchemaUpdateParameters.java
index 40b0db2c16..ff14ddf385 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/SchemaUpdateParameters.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/SchemaUpdateParameters.java
@@ -91,7 +91,7 @@ default SchemaUpdateParameters setStrictValidation(boolean flag) {
* @return
*/
default boolean isStrictValidation() {
- return BooleanUtils.toBooleanDefaultIfNull(Boolean.valueOf(getParameter(STRICT_VALIDATION_KEY)), false);
+ return BooleanUtils.toBooleanDefaultIfNull(BooleanUtils.toBooleanObject(getParameter(STRICT_VALIDATION_KEY)), false);
}
}
diff --git a/rest-model/src/main/java/com/gentics/mesh/parameter/image/ImageRect.java b/rest-model/src/main/java/com/gentics/mesh/parameter/image/ImageRect.java
index 607fceb6c6..d5e90c9b6f 100644
--- a/rest-model/src/main/java/com/gentics/mesh/parameter/image/ImageRect.java
+++ b/rest-model/src/main/java/com/gentics/mesh/parameter/image/ImageRect.java
@@ -6,12 +6,13 @@
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.gentics.mesh.core.rest.common.RestModel;
import com.gentics.mesh.parameter.ImageManipulationParameters;
/**
* Class which represents an image rectangular.
*/
-public class ImageRect {
+public class ImageRect implements RestModel {
private int startX;
private int startY;
diff --git a/tests/common/src/main/java/com/gentics/mesh/test/ClientHelper.java b/tests/common/src/main/java/com/gentics/mesh/test/ClientHelper.java
index 7b9b920cb6..3dc401bc24 100644
--- a/tests/common/src/main/java/com/gentics/mesh/test/ClientHelper.java
+++ b/tests/common/src/main/java/com/gentics/mesh/test/ClientHelper.java
@@ -10,6 +10,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -18,6 +20,7 @@
import com.gentics.mesh.core.data.i18n.I18NUtil;
import com.gentics.mesh.core.rest.common.GenericMessageResponse;
import com.gentics.mesh.core.rest.error.GenericRestException;
+import com.gentics.mesh.json.JsonUtil;
import com.gentics.mesh.rest.client.MeshRequest;
import com.gentics.mesh.rest.client.MeshResponse;
import com.gentics.mesh.rest.client.MeshRestClientMessageException;
@@ -25,6 +28,7 @@
import com.gentics.mesh.test.context.ClientHandler;
import com.gentics.mesh.test.util.TestUtils;
import com.gentics.mesh.util.ETag;
+import com.google.gson.JsonSyntaxException;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.reactivex.Observable;
@@ -159,6 +163,17 @@ public static MeshRestClientMessageException call(ClientHandler handler,
Throwable cause = e.getCause();
if (cause instanceof MeshRestClientMessageException) {
error = (MeshRestClientMessageException) e.getCause();
+ } else if (cause.getClass().getCanonicalName().equals("org.openapitools.client.ApiException")) {
+ try {
+ String responseBody = (String) Arrays.stream(cause.getClass().getDeclaredMethods()).filter(m -> m.getName().equals("getResponseBody") && m.getParameterCount() == 0).findAny().orElseThrow(() -> new IllegalStateException(e)).invoke(cause);
+ int code = (int) Arrays.stream(cause.getClass().getDeclaredMethods()).filter(m -> m.getName().equals("getCode") && m.getParameterCount() == 0).findAny().orElseThrow(() -> new IllegalStateException(e)).invoke(cause);
+ String message = (String) Arrays.stream(cause.getClass().getDeclaredMethods()).filter(m -> m.getName().equals("getMessage") && m.getParameterCount() == 0).findAny().orElseThrow(() -> new IllegalStateException(e)).invoke(cause);
+ error = new MeshRestClientMessageException(code, message, JsonUtil.readValue(responseBody, GenericMessageResponse.class), null, null);
+ } catch (JsonSyntaxException | GenericRestException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException | IllegalStateException
+ | SecurityException e1) {
+ throw new RuntimeException(e1);
+ }
} else {
throw (RuntimeException) e;
}
@@ -170,9 +185,7 @@ public static MeshRestClientMessageException call(ClientHandler handler,
} else {
expectException(error, status, bodyMessageI18nKey, i18nParams);
}
- if (error instanceof MeshRestClientMessageException) {
- return (MeshRestClientMessageException) e.getCause();
- }
+ return error;
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/tests/common/src/main/java/com/gentics/mesh/test/context/MeshTestContext.java b/tests/common/src/main/java/com/gentics/mesh/test/context/MeshTestContext.java
index 074b2a0e59..eec8b39796 100644
--- a/tests/common/src/main/java/com/gentics/mesh/test/context/MeshTestContext.java
+++ b/tests/common/src/main/java/com/gentics/mesh/test/context/MeshTestContext.java
@@ -8,6 +8,7 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
import java.nio.file.NoSuchFileException;
import java.security.cert.CertificateException;
import java.time.Duration;
@@ -72,7 +73,6 @@
import com.gentics.mesh.search.TrackingSearchProvider;
import com.gentics.mesh.search.TrackingSearchProviderImpl;
import com.gentics.mesh.search.verticle.ElasticsearchProcessVerticle;
-import com.gentics.mesh.test.ElasticsearchTestMode;
import com.gentics.mesh.test.MeshCoreOptionChanger;
import com.gentics.mesh.test.MeshInstanceProvider;
import com.gentics.mesh.test.MeshTestActions;
@@ -1020,6 +1020,20 @@ public Mesh getMesh() {
return mesh;
}
+ private MeshRestClient createRestClient(MeshRestClientConfig config) {
+ String customMeshRestClient = System.getenv("MESH_REST_CLIENT_CLASS");
+ if (StringUtils.isNotBlank(customMeshRestClient)) {
+ try {
+ return (MeshRestClient) Class.forName(customMeshRestClient).getConstructor(MeshRestClientConfig.class, OkHttpClient.class).newInstance(config, okHttp);
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | NoSuchMethodException | SecurityException
+ | ClassNotFoundException e) {
+ LOG.error("Could not instantiate MeshRestClient from class " + customMeshRestClient, e);
+ }
+ }
+ return MeshRestClient.create(config, okHttp);
+ }
+
private void setupRestEndpoints(MeshTestSetting settings) throws Exception {
mesh.getOptions().getUploadOptions().setByteLimit(Long.MAX_VALUE);
@@ -1034,11 +1048,11 @@ private void setupRestEndpoints(MeshTestSetting settings) throws Exception {
.setBasePath(CURRENT_API_BASE_PATH)
.setSsl(false);
- MeshRestClient httpClient = MeshRestClient.create(httpConfigBuilder.build(), okHttp);
+ MeshRestClient httpClient = createRestClient(httpConfigBuilder.build());
httpClient.setLogin(getData().user().getUsername(), getData().getUserInfo().getPassword());
httpClient.login().blockingGet();
clients.put("http_v" + CURRENT_API_VERSION, httpClient);
- anonymousClients.put("http_v" + CURRENT_API_VERSION, MeshRestClient.create(httpConfigBuilder.build(), okHttp));
+ anonymousClients.put("http_v" + CURRENT_API_VERSION, createRestClient(httpConfigBuilder.build()));
// Setup SSL client if needed
SSLTestMode ssl = settings.ssl();
diff --git a/tests/tests-core/pom.xml b/tests/tests-core/pom.xml
index 8dd04042c0..1f95f9ec7e 100644
--- a/tests/tests-core/pom.xml
+++ b/tests/tests-core/pom.xml
@@ -24,6 +24,12 @@
com.gentics.mesh
tests-mesh-common
+
+
+ com.github.java-json-tools
+ json-schema-validator
+
+
com.gentics.mesh
@@ -79,12 +85,46 @@
org.mock-server
mockserver-junit-rule
5.9.0
+
+
+ com.github.java-json-tools
+ json-schema-validator
+
+
+
+
+ com.github.java-json-tools
+ json-schema-validator
+ 2.2.14
org.apache.httpcomponents
httpcore
4.4.13
+
+ io.swagger.parser.v3
+ swagger-parser
+ 2.1.39
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ 2.1.1
+
+
+ com.google.code.gson
+ gson
+
+
+ io.gsonfire
+ gson-fire
+ 1.9.0
+
+
+ com.squareup.okhttp3
+ logging-interceptor
+
@@ -103,6 +143,29 @@
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.5.0
+
+
+ Generate OpenAPI
+
+ exec
+
+ generate-resources
+
+ ${env.JAVA_HOME}/bin/java
+
+ -classpath
+
+ com.gentics.mesh.generator.runner.OpenAPISpecGeneratorRunner
+ ${basedir}/../../doc/src/main/docs/generated
+
+
+
+
+
maven-invoker-plugin
3.1.0
@@ -135,6 +198,57 @@
+
+ org.openapitools
+ openapi-generator-maven-plugin
+ 7.19.0
+
+
+ generate-client
+
+ generate
+
+ process-resources
+
+ ${basedir}/../../doc/src/main/docs/generated/api/openapi.yaml
+
+ java
+ false
+ false
+ true
+ false
+
+ true
+ true
+ false
+ true
+ /
+ false
+
+ okhttp-gson
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ add-sources
+ generate-sources
+
+ add-source
+
+
+
+ ${project.build.directory}/generated-sources/openapi
+ ${project.build.directory}/generated-sources/annotations
+
+
+
+
+
diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/cli/MeshIntegerationTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/cli/MeshIntegerationTest.java
index bbc9acfcd2..0ca9b86613 100644
--- a/tests/tests-core/src/main/java/com/gentics/mesh/cli/MeshIntegerationTest.java
+++ b/tests/tests-core/src/main/java/com/gentics/mesh/cli/MeshIntegerationTest.java
@@ -7,6 +7,7 @@
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.FixMethodOrder;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.MethodSorters;
@@ -28,6 +29,7 @@ public void cleanup() throws IOException {
}
@Test
+ @Ignore("Makes nothing but heavy runtime load")
public void testStartup() throws Exception {
MeshOptions options = getOptions();
Mesh mesh = Mesh.create(options);
diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/client/MeshRestClientTokenTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/client/MeshRestClientTokenTest.java
index e21902f8d4..5697d9c571 100644
--- a/tests/tests-core/src/main/java/com/gentics/mesh/client/MeshRestClientTokenTest.java
+++ b/tests/tests-core/src/main/java/com/gentics/mesh/client/MeshRestClientTokenTest.java
@@ -4,14 +4,19 @@
import static com.gentics.mesh.test.ClientHelper.call;
import static com.gentics.mesh.test.ElasticsearchTestMode.NONE;
import static com.gentics.mesh.test.TestSize.PROJECT;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Test;
import com.gentics.mesh.demo.UserInfo;
import com.gentics.mesh.etc.config.MeshOptions;
+import com.gentics.mesh.rest.client.MeshRestClientMessageException;
import com.gentics.mesh.test.MeshOptionChanger;
import com.gentics.mesh.test.MeshTestSetting;
import com.gentics.mesh.test.TestDataProvider;
@@ -67,13 +72,34 @@ public void setUp() throws Exception {
public void testLogin() throws Exception {
client().setLogin(username, password).login().blockingGet();
- // now get "me" for 10 seconds (once every second). This will fail, when the token expires
- Flowable.intervalRange(0, 10, 0, 1, TimeUnit.SECONDS).flatMapSingle(v -> {
- return client().me().toSingle();
- }).doOnNext(response -> {
- // assert that we still are the correct user
- assertThat(response).hasName(username);
- }).blockingSubscribe();
+ AtomicLong startAt = new AtomicLong(System.currentTimeMillis());
+ try {
+ // now get "me" for 10 seconds (once every second). This will fail in 5 (TOKEN_EXPIRATION_TIME_SECONDS), when the token expires
+ Flowable.intervalRange(0, 10, 0, 1, TimeUnit.SECONDS).flatMapSingle(v -> {
+ return client().me().toSingle();
+ }).doOnError(t -> {
+ // assert the expired token
+ assertThat((System.currentTimeMillis() - startAt.get())).as("Token expiration time").isGreaterThan(TOKEN_EXPIRATION_TIME_SECONDS * 1000);
+ Consumer assertException = tt -> {
+ assertThat(tt.getStatusCode()).as("REST client error status").isEqualTo(401);
+ };
+ if (t instanceof MeshRestClientMessageException tt) {
+ assertException.accept(tt);
+ } else if (t.getCause() instanceof MeshRestClientMessageException tt) {
+ assertException.accept(tt);
+ } else {
+ fail(t);
+ }
+ }).doOnNext(response -> {
+ // assert that we still are the correct user
+ assertThat(response).hasName(username);
+ // assert the inexpired token
+ assertThat((System.currentTimeMillis() - startAt.get())).as("Token expiration time").isLessThanOrEqualTo(TOKEN_EXPIRATION_TIME_SECONDS * 1000);
+ }).blockingSubscribe();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // already asserted
+ }
}
/**
diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupEndpointTest.java
index a219525990..30ff5c4076 100644
--- a/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupEndpointTest.java
+++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupEndpointTest.java
@@ -113,9 +113,9 @@ public void testCreateWithUuid() throws Exception {
final String name = "New Name";
String uuid = UUIDUtil.randomUUID();
- GroupUpdateRequest request = new GroupUpdateRequest();
+ GroupCreateRequest request = new GroupCreateRequest();
request.setName(name);
- GroupResponse restGroup = call(() -> client().updateGroup(uuid, request));
+ GroupResponse restGroup = call(() -> client().createGroup(uuid, request));
waitForSearchIdleEvent();
diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/openapi/OpenAPIEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/openapi/OpenAPIEndpointTest.java
new file mode 100644
index 0000000000..e5ce5e7299
--- /dev/null
+++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/openapi/OpenAPIEndpointTest.java
@@ -0,0 +1,94 @@
+package com.gentics.mesh.core.openapi;
+
+import static com.gentics.mesh.test.ClientHelper.call;
+import static com.gentics.mesh.test.TestSize.FULL;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.gentics.mesh.MeshVersion;
+import com.gentics.mesh.test.MeshTestSetting;
+import com.gentics.mesh.test.context.AbstractMeshTest;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.parser.OpenAPIV3Parser;
+import io.swagger.v3.parser.core.models.ParseOptions;
+import io.swagger.v3.parser.core.models.SwaggerParseResult;
+
+@MeshTestSetting(testSize = FULL, startServer = true)
+@RunWith(Parameterized.class)
+public class OpenAPIEndpointTest extends AbstractMeshTest {
+
+ @Parameters(name = "{index}: no Mesh Client = {0}, OpenAPI disabled: {1}")
+ public static Collection