This is an automated email from the ASF dual-hosted git repository.
benjobs pushed a commit to branch dev-2.1.5
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git
The following commit(s) were added to refs/heads/dev-2.1.5 by this push:
new 47abdca3b [Improve] openAPI backend service layer improvement
47abdca3b is described below
commit 47abdca3b5aaf9e1937ab9fb285bb3677881f7f2
Author: benjobs <[email protected]>
AuthorDate: Fri Jul 26 14:39:24 2024 +0800
[Improve] openAPI backend service layer improvement
---
.../streampark/common/util/CURLBuilder.scala | 19 +-
.../streampark/common/util/ReflectUtils.scala | 26 ++-
.../apache/streampark/console/base/util/Tuple.java | 62 ++++++
.../streampark/console/base/util/Tuple1.java | 113 +++++++++++
.../streampark/console/base/util/Tuple2.java | 163 +++++++++++++++
.../streampark/console/base/util/Tuple3.java | 171 ++++++++++++++++
.../streampark/console/base/util/Tuple4.java | 187 ++++++++++++++++++
.../annotation/{ApiAccess.java => OpenAPI.java} | 24 ++-
.../console/core/aspect/StreamParkAspect.java | 6 +-
.../ApiAccess.java => bean/OpenAPISchema.java} | 43 +++-
.../console/core/component/OpenAPIComponent.java | 218 +++++++++++++++++++++
.../core/controller/ApplicationController.java | 2 -
.../console/core/controller/OpenAPIController.java | 156 +++++++++++++++
13 files changed, 1158 insertions(+), 32 deletions(-)
diff --git
a/streampark-common/src/main/scala/org/apache/streampark/common/util/CURLBuilder.scala
b/streampark-common/src/main/scala/org/apache/streampark/common/util/CURLBuilder.scala
index ef8bde57d..a35db77cd 100644
---
a/streampark-common/src/main/scala/org/apache/streampark/common/util/CURLBuilder.scala
+++
b/streampark-common/src/main/scala/org/apache/streampark/common/util/CURLBuilder.scala
@@ -17,35 +17,32 @@
package org.apache.streampark.common.util
import java.util
+import java.util.{HashMap => JavaHashMap}
import scala.collection.JavaConversions._
class CURLBuilder(val url: String) {
- val headers: util.Map[String, String] = new util.HashMap[String, String]
+ private[this] val headers: util.Map[String, String] = new
JavaHashMap[String, String]
- val formDatas: util.Map[String, String] = new util.HashMap[String, String]
+ private[this] val formData: util.Map[String, String] = new
JavaHashMap[String, String]
def addHeader(k: String, v: String): CURLBuilder = {
this.headers.put(k, v)
this
}
- def addFormData(k: String, v: String): CURLBuilder = {
- this.formDatas.put(k, v)
+ def addFormData(k: String, v: java.io.Serializable): CURLBuilder = {
+ this.formData.put(k, v.toString)
this
}
def build: String = {
- require(url != null, "[StreamPark] cURL build failed, url must not be
null")
+ require(url != null, "[StreamPark] CURL build failed, url must not be
null")
val cURL = new StringBuilder("curl -X POST ")
cURL.append(String.format("'%s' \\\n", url))
- for (headerKey <- headers.keySet) {
- cURL.append(String.format("-H \'%s: %s\' \\\n", headerKey,
headers.get(headerKey)))
- }
- for (field <- formDatas.keySet) {
- cURL.append(String.format("--data-urlencode \'%s=%s\' \\\n", field,
formDatas.get(field)))
- }
+ headers.keySet.foreach(h => cURL.append(String.format("-H \'%s: %s\'
\\\n", h, headers.get(h))))
+ formData.foreach(k => cURL.append(String.format("--data-urlencode
\'%s=%s\' \\\n", k._1, k._2)))
cURL.append("-i")
cURL.toString
}
diff --git
a/streampark-common/src/main/scala/org/apache/streampark/common/util/ReflectUtils.scala
b/streampark-common/src/main/scala/org/apache/streampark/common/util/ReflectUtils.scala
index ef2deefc4..3a5183388 100644
---
a/streampark-common/src/main/scala/org/apache/streampark/common/util/ReflectUtils.scala
+++
b/streampark-common/src/main/scala/org/apache/streampark/common/util/ReflectUtils.scala
@@ -19,9 +19,11 @@ package org.apache.streampark.common.util
import org.apache.commons.lang3.StringUtils
-import java.lang.reflect.{Field, Modifier}
+import java.lang.annotation.Annotation
+import java.lang.reflect.{Field, Method, Modifier}
import java.util.Objects
+import scala.collection.JavaConverters._
import scala.util.{Failure, Success, Try}
object ReflectUtils extends Logger {
@@ -40,7 +42,10 @@ object ReflectUtils extends Logger {
*/
@throws[SecurityException]
def getField(beanClass: Class[_], name: String): Field = {
- Try(beanClass.getDeclaredFields.filter(f => Objects.equals(name,
f.getName)).head)
+ Try(
+ beanClass.getDeclaredFields
+ .filter(f => Objects.equals(name, f.getName))
+ .head)
.getOrElse(null)
}
@@ -50,8 +55,9 @@ object ReflectUtils extends Logger {
}
def getFieldValue(obj: Any, field: Field): Any = {
- if (obj == null || field == null) null
- else {
+ if (obj == null || field == null) {
+ null
+ } else {
field.setAccessible(true)
field.get(obj) match {
case Success(v) => v
@@ -62,11 +68,11 @@ object ReflectUtils extends Logger {
def setFieldValue(obj: Any, fieldName: String, value: Any): Unit = {
val field = getAccessibleField(obj, fieldName)
- if (field == null)
+ if (field == null) {
throw new IllegalArgumentException(
"Could not find field [" + fieldName + "] on target [" + obj + "]")
- try
- field.set(obj, value)
+ }
+ try field.set(obj, value)
catch {
case e: IllegalAccessException =>
logError("Failed to assign to the element.", e)
@@ -101,4 +107,10 @@ object ReflectUtils extends Logger {
}
}
+ def getMethodsByAnnotation(
+ beanClass: Class[_],
+ annotClazz: Class[_ <: Annotation]): java.util.List[Method] = {
+ beanClass.getDeclaredMethods.filter(_.getDeclaredAnnotation(annotClazz) !=
null).toList.asJava
+ }
+
}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple.java
new file mode 100644
index 000000000..f80d6bd38
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.base.util;
+
+/**
+ * The base class of all tuples. Tuples have a fix length and contain a set of
fields, which may all
+ * be of different types. Because Tuples are strongly typed, each distinct
tuple length is
+ * represented by its own class. Tuples exists with up to 25 fields and are
described in the classes
+ * {@link Tuple1} to {@link Tuple4}.
+ *
+ * <p>The fields in the tuples may be accessed directly a public fields, or
via position (zero
+ * indexed) {@link #get(int)}.
+ *
+ * <p>Tuples are in principle serializable. However, they may contain
non-serializable fields, in
+ * which case serialization will fail.
+ */
+public abstract class Tuple implements java.io.Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Gets the field at the specified position.
+ *
+ * @param pos The position of the field, zero indexed.
+ * @return The field at the specified position.
+ * @throws IndexOutOfBoundsException Thrown, if the position is negative, or
equal to, or larger
+ * than the number of fields.
+ */
+ public abstract <T> T get(int pos);
+
+ /**
+ * Sets the field at the specified position.
+ *
+ * @param value The value to be assigned to the field at the specified
position.
+ * @param pos The position of the field, zero indexed.
+ * @throws IndexOutOfBoundsException Thrown, if the position is negative, or
equal to, or larger
+ * than the number of fields.
+ */
+ public abstract <T> void set(T value, int pos);
+
+ /**
+ * Shallow tuple copy.
+ *
+ * @return A new Tuple with the same fields as this.
+ */
+ public abstract <T extends Tuple> T copy();
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple1.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple1.java
new file mode 100644
index 000000000..1a6f79d0b
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple1.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.base.util;
+
+import java.util.Objects;
+
+public class Tuple1<T0> extends Tuple {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Field 0 of the tuple. */
+ public T0 t1;
+
+ /** Creates a new tuple where all fields are null. */
+ public Tuple1() {}
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
+ *
+ * @param t0 The value for field 0
+ */
+ public Tuple1(T0 t0) {
+ this.t1 = t0;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T get(int pos) {
+ if (pos == 0) {
+ return (T) this.t1;
+ }
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> void set(T value, int pos) {
+ if (pos == 0) {
+ this.t1 = (T0) value;
+ } else {
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ /**
+ * Sets new values to all fields of the tuple.
+ *
+ * @param f0 The value for field 0
+ */
+ public void set(T0 f0) {
+ this.t1 = f0;
+ }
+
+ /**
+ * Deep equality for tuples by calling equals() on the tuple members.
+ *
+ * @param o the object checked for equality
+ * @return true if this is equal to o.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Tuple1)) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Tuple1 tuple = (Tuple1) o;
+ return Objects.equals(t1, tuple.t1);
+ }
+
+ @Override
+ public int hashCode() {
+ return t1 != null ? t1.hashCode() : 0;
+ }
+
+ /**
+ * Shallow tuple copy.
+ *
+ * @return A new Tuple with the same fields as this.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Tuple1<T0> copy() {
+ return new Tuple1<>(this.t1);
+ }
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
This is more convenient
+ * than using the constructor, because the compiler can infer the generic
type arguments
+ * implicitly. For example: {@code Tuple3.of(n, x, s)} instead of {@code new
Tuple3<Integer,
+ * Double, String>(n, x, s)}
+ */
+ public static <T0> Tuple1<T0> of(T0 f0) {
+ return new Tuple1<>(f0);
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple2.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple2.java
new file mode 100644
index 000000000..886beb113
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple2.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.base.util;
+
+import java.util.Objects;
+
+/**
+ * A tuple with 2 fields. Tuples are strongly typed; each field may be of a
separate type. The
+ * fields of the tuple can be accessed directly as public fields (f0, f1, ...)
or via their position
+ * through the {@link #get(int)} method. The tuple field positions start at
zero.
+ *
+ * <p>Tuples are mutable types, meaning that their fields can be re-assigned.
This allows functions
+ * that work with Tuples to reuse objects in order to reduce pressure on the
garbage collector.
+ *
+ * <p>Warning: If you subclass Tuple2, then be sure to either
+ *
+ * <ul>
+ * <li>not add any new fields, or
+ * <li>make it a POJO, and always declare the element type of your
DataStreams/DataSets to your
+ * descendant type. (That is, if you have a "class Foo extends Tuple2",
then don't use
+ * instances of Foo in a DataStream<Tuple2> /
DataSet<Tuple2>, but declare it as
+ * DataStream<Foo> / DataSet<Foo>.)
+ * </ul>
+ *
+ * @see Tuple
+ * @param <T0> The type of field 0
+ * @param <T1> The type of field 1
+ */
+public class Tuple2<T0, T1> extends Tuple {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Field 0 of the tuple. */
+ public T0 t1;
+ /** Field 1 of the tuple. */
+ public T1 t2;
+
+ /** Creates a new tuple where all fields are null. */
+ public Tuple2() {}
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
+ *
+ * @param t0 The value for field 0
+ * @param t1 The value for field 1
+ */
+ public Tuple2(T0 t0, T1 t1) {
+ this.t1 = t0;
+ this.t2 = t1;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T get(int pos) {
+ switch (pos) {
+ case 0:
+ return (T) this.t1;
+ case 1:
+ return (T) this.t2;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> void set(T value, int pos) {
+ switch (pos) {
+ case 0:
+ this.t1 = (T0) value;
+ break;
+ case 1:
+ this.t2 = (T1) value;
+ break;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ /**
+ * Sets new values to all fields of the tuple.
+ *
+ * @param f0 The value for field 0
+ * @param f1 The value for field 1
+ */
+ public void set(T0 f0, T1 f1) {
+ this.t1 = f0;
+ this.t2 = f1;
+ }
+
+ /**
+ * Returns a shallow copy of the tuple with swapped values.
+ *
+ * @return shallow copy of the tuple with swapped values
+ */
+ public Tuple2<T1, T0> swap() {
+ return new Tuple2<T1, T0>(t2, t1);
+ }
+
+ /**
+ * Deep equality for tuples by calling equals() on the tuple members.
+ *
+ * @param o the object checked for equality
+ * @return true if this is equal to o.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Tuple2)) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Tuple2 tuple = (Tuple2) o;
+ if (!Objects.equals(t1, tuple.t1)) {
+ return false;
+ }
+ return Objects.equals(t2, tuple.t2);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = t1 != null ? t1.hashCode() : 0;
+ result = 31 * result + (t2 != null ? t2.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * Shallow tuple copy.
+ *
+ * @return A new Tuple with the same fields as this.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Tuple2<T0, T1> copy() {
+ return new Tuple2<>(this.t1, this.t2);
+ }
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
This is more convenient
+ * than using the constructor, because the compiler can infer the generic
type arguments
+ * implicitly. For example: {@code Tuple3.of(n, x, s)} instead of {@code new
Tuple3<Integer,
+ * Double, String>(n, x, s)}
+ */
+ public static <T0, T1> Tuple2<T0, T1> of(T0 f0, T1 f1) {
+ return new Tuple2<>(f0, f1);
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple3.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple3.java
new file mode 100644
index 000000000..802262418
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple3.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.base.util;
+
+import java.util.Objects;
+
+/**
+ * A tuple with 3 fields. Tuples are strongly typed; each field may be of a
separate type. The
+ * fields of the tuple can be accessed directly as public fields (f0, f1, ...)
or via their position
+ * through the {@link #get(int)} method. The tuple field positions start at
zero.
+ *
+ * <p>Tuples are mutable types, meaning that their fields can be re-assigned.
This allows functions
+ * that work with Tuples to reuse objects in order to reduce pressure on the
garbage collector.
+ *
+ * <p>Warning: If you subclass Tuple3, then be sure to either
+ *
+ * <ul>
+ * <li>not add any new fields, or
+ * <li>make it a POJO, and always declare the element type of your
DataStreams/DataSets to your
+ * descendant type. (That is, if you have a "class Foo extends Tuple3",
then don't use
+ * instances of Foo in a DataStream<Tuple3> /
DataSet<Tuple3>, but declare it as
+ * DataStream<Foo> / DataSet<Foo>.)
+ * </ul>
+ *
+ * @see Tuple
+ * @param <T0> The type of field 0
+ * @param <T1> The type of field 1
+ * @param <T2> The type of field 2
+ */
+public class Tuple3<T0, T1, T2> extends Tuple {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Field 0 of the tuple. */
+ public T0 t1;
+ /** Field 1 of the tuple. */
+ public T1 t2;
+ /** Field 2 of the tuple. */
+ public T2 t3;
+
+ /** Creates a new tuple where all fields are null. */
+ public Tuple3() {}
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
+ *
+ * @param t0 The value for field 0
+ * @param t1 The value for field 1
+ * @param t2 The value for field 2
+ */
+ public Tuple3(T0 t0, T1 t1, T2 t2) {
+ this.t1 = t0;
+ this.t2 = t1;
+ this.t3 = t2;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T get(int pos) {
+ switch (pos) {
+ case 0:
+ return (T) this.t1;
+ case 1:
+ return (T) this.t2;
+ case 2:
+ return (T) this.t3;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> void set(T value, int pos) {
+ switch (pos) {
+ case 0:
+ this.t1 = (T0) value;
+ break;
+ case 1:
+ this.t2 = (T1) value;
+ break;
+ case 2:
+ this.t3 = (T2) value;
+ break;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ /**
+ * Sets new values to all fields of the tuple.
+ *
+ * @param f0 The value for field 0
+ * @param f1 The value for field 1
+ * @param f2 The value for field 2
+ */
+ public void set(T0 f0, T1 f1, T2 f2) {
+ this.t1 = f0;
+ this.t2 = f1;
+ this.t3 = f2;
+ }
+
+ /**
+ * Deep equality for tuples by calling equals() on the tuple members.
+ *
+ * @param o the object checked for equality
+ * @return true if this is equal to o.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Tuple3)) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Tuple3 tuple = (Tuple3) o;
+ if (!Objects.equals(t1, tuple.t1)) {
+ return false;
+ }
+ if (!Objects.equals(t2, tuple.t2)) {
+ return false;
+ }
+ return Objects.equals(t3, tuple.t3);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = t1 != null ? t1.hashCode() : 0;
+ result = 31 * result + (t2 != null ? t2.hashCode() : 0);
+ result = 31 * result + (t3 != null ? t3.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * Shallow tuple copy.
+ *
+ * @return A new Tuple with the same fields as this.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Tuple3<T0, T1, T2> copy() {
+ return new Tuple3<>(this.t1, this.t2, this.t3);
+ }
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
This is more convenient
+ * than using the constructor, because the compiler can infer the generic
type arguments
+ * implicitly. For example: {@code Tuple3.of(n, x, s)} instead of {@code new
Tuple3<Integer,
+ * Double, String>(n, x, s)}
+ */
+ public static <T0, T1, T2> Tuple3<T0, T1, T2> of(T0 f0, T1 f1, T2 f2) {
+ return new Tuple3<>(f0, f1, f2);
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple4.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple4.java
new file mode 100644
index 000000000..0296d33e5
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Tuple4.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.base.util;
+
+import java.util.Objects;
+
+/**
+ * A tuple with 4 fields. Tuples are strongly typed; each field may be of a
separate type. The
+ * fields of the tuple can be accessed directly as public fields (f0, f1, ...)
or via their position
+ * through the {@link #get(int)} method. The tuple field positions start at
zero.
+ *
+ * <p>Tuples are mutable types, meaning that their fields can be re-assigned.
This allows functions
+ * that work with Tuples to reuse objects in order to reduce pressure on the
garbage collector.
+ *
+ * <p>Warning: If you subclass Tuple4, then be sure to either
+ *
+ * <ul>
+ * <li>not add any new fields, or
+ * <li>make it a POJO, and always declare the element type of your
DataStreams/DataSets to your
+ * descendant type. (That is, if you have a "class Foo extends Tuple4",
then don't use
+ * instances of Foo in a DataStream<Tuple4> /
DataSet<Tuple4>, but declare it as
+ * DataStream<Foo> / DataSet<Foo>.)
+ * </ul>
+ *
+ * @see Tuple
+ * @param <T0> The type of field 0
+ * @param <T1> The type of field 1
+ * @param <T2> The type of field 2
+ * @param <T3> The type of field 3
+ */
+public class Tuple4<T0, T1, T2, T3> extends Tuple {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Field 0 of the tuple. */
+ public T0 t1;
+ /** Field 1 of the tuple. */
+ public T1 t2;
+ /** Field 2 of the tuple. */
+ public T2 t3;
+ /** Field 3 of the tuple. */
+ public T3 t4;
+
+ /** Creates a new tuple where all fields are null. */
+ public Tuple4() {}
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
+ *
+ * @param t0 The value for field 0
+ * @param t1 The value for field 1
+ * @param t2 The value for field 2
+ * @param t4 The value for field 3
+ */
+ public Tuple4(T0 t0, T1 t1, T2 t2, T3 t4) {
+ this.t1 = t0;
+ this.t2 = t1;
+ this.t3 = t2;
+ this.t4 = t4;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T get(int pos) {
+ switch (pos) {
+ case 0:
+ return (T) this.t1;
+ case 1:
+ return (T) this.t2;
+ case 2:
+ return (T) this.t3;
+ case 3:
+ return (T) this.t4;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> void set(T value, int pos) {
+ switch (pos) {
+ case 0:
+ this.t1 = (T0) value;
+ break;
+ case 1:
+ this.t2 = (T1) value;
+ break;
+ case 2:
+ this.t3 = (T2) value;
+ break;
+ case 3:
+ this.t4 = (T3) value;
+ break;
+ default:
+ throw new IndexOutOfBoundsException(String.valueOf(pos));
+ }
+ }
+
+ /**
+ * Sets new values to all fields of the tuple.
+ *
+ * @param f0 The value for field 0
+ * @param f1 The value for field 1
+ * @param f2 The value for field 2
+ * @param f3 The value for field 3
+ */
+ public void set(T0 f0, T1 f1, T2 f2, T3 f3) {
+ this.t1 = f0;
+ this.t2 = f1;
+ this.t3 = f2;
+ this.t4 = f3;
+ }
+
+ /**
+ * Deep equality for tuples by calling equals() on the tuple members.
+ *
+ * @param o the object checked for equality
+ * @return true if this is equal to o.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Tuple4)) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Tuple4 tuple = (Tuple4) o;
+ if (!Objects.equals(t1, tuple.t1)) {
+ return false;
+ }
+ if (!Objects.equals(t2, tuple.t2)) {
+ return false;
+ }
+ if (!Objects.equals(t3, tuple.t3)) {
+ return false;
+ }
+ return Objects.equals(t4, tuple.t4);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = t1 != null ? t1.hashCode() : 0;
+ result = 31 * result + (t2 != null ? t2.hashCode() : 0);
+ result = 31 * result + (t3 != null ? t3.hashCode() : 0);
+ result = 31 * result + (t4 != null ? t4.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * Shallow tuple copy.
+ *
+ * @return A new Tuple with the same fields as this.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Tuple4<T0, T1, T2, T3> copy() {
+ return new Tuple4<>(this.t1, this.t2, this.t3, this.t4);
+ }
+
+ /**
+ * Creates a new tuple and assigns the given values to the tuple's fields.
This is more convenient
+ * than using the constructor, because the compiler can infer the generic
type arguments
+ * implicitly. For example: {@code Tuple3.of(n, x, s)} instead of {@code new
Tuple3<Integer,
+ * Double, String>(n, x, s)}
+ */
+ public static <T0, T1, T2, T3> Tuple4<T0, T1, T2, T3> of(T0 f0, T1 f1, T2
f2, T3 f3) {
+ return new Tuple4<>(f0, f1, f2, f3);
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/OpenAPI.java
similarity index 77%
copy from
streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
copy to
streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/OpenAPI.java
index 0ef500cff..02f072a1c 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/OpenAPI.java
@@ -24,4 +24,26 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
-public @interface ApiAccess {}
+public @interface OpenAPI {
+
+ String name() default "";
+
+ Param[] header() default {};
+
+ Param[] param() default {};
+
+ @interface Param {
+
+ String name();
+
+ String description();
+
+ boolean required();
+
+ Class<?> type();
+
+ String defaultValue() default "";
+
+ String bindFor() default "";
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
index 352362e66..82c9cc484 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
@@ -19,7 +19,7 @@ package org.apache.streampark.console.core.aspect;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.ApiAlertException;
-import org.apache.streampark.console.core.annotation.ApiAccess;
+import org.apache.streampark.console.core.annotation.OpenAPI;
import org.apache.streampark.console.core.annotation.PermissionScope;
import org.apache.streampark.console.core.entity.Application;
import org.apache.streampark.console.core.enums.UserType;
@@ -72,8 +72,8 @@ public class StreamParkAspect {
Boolean isApi =
(Boolean)
SecurityUtils.getSubject().getSession().getAttribute(AccessToken.IS_API_TOKEN);
if (isApi != null && isApi) {
- ApiAccess apiAccess =
methodSignature.getMethod().getAnnotation(ApiAccess.class);
- if (apiAccess == null) {
+ OpenAPI openAPI =
methodSignature.getMethod().getAnnotation(OpenAPI.class);
+ if (openAPI == null) {
throw new ApiAlertException("current api unsupported!");
}
}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
similarity index 58%
rename from
streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
rename to
streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
index 0ef500cff..504724bd0 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiAccess.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
@@ -15,13 +15,40 @@
* limitations under the License.
*/
-package org.apache.streampark.console.core.annotation;
+package org.apache.streampark.console.core.bean;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ApiAccess {}
+import java.util.List;
+
+@Getter
+@Setter
+public class OpenAPISchema {
+
+ private String url;
+
+ private String method;
+
+ private List<Schema> header;
+
+ private List<Schema> schema;
+
+ @Getter
+ @Setter
+ public static class Schema {
+
+ private String name;
+
+ private String type;
+
+ private boolean required;
+
+ private String description;
+
+ private String defaultValue;
+
+ @JsonIgnore private String bindFor;
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
new file mode 100644
index 000000000..038b69109
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.core.component;
+
+import org.apache.streampark.common.util.CURLBuilder;
+import org.apache.streampark.common.util.ReflectUtils;
+import org.apache.streampark.console.base.util.Tuple2;
+import org.apache.streampark.console.core.annotation.OpenAPI;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+import org.apache.streampark.console.core.controller.OpenAPIController;
+import org.apache.streampark.console.core.service.ServiceHelper;
+import org.apache.streampark.console.system.service.AccessTokenService;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Component
+public class OpenAPIComponent {
+
+ @Autowired private AccessTokenService accessTokenService;
+
+ @Autowired private ServiceHelper serviceHelper;
+
+ private final Map<String, String> types = new HashMap<>();
+
+ private final Map<String, OpenAPISchema> schemas = new HashMap<>();
+
+ public synchronized OpenAPISchema getOpenAPISchema(String name) {
+ if (schemas.isEmpty()) {
+ try {
+ initOpenAPISchema();
+ } catch (Exception e) {
+ log.error("InitOpenAPISchema failed", e);
+ }
+ }
+ return schemas.get(name);
+ }
+
+ public String getOpenApiCUrl(String baseUrl, Long appId, Long teamId, String
name) {
+ OpenAPISchema schema = this.getOpenAPISchema(name);
+ if (schema == null) {
+ throw new UnsupportedOperationException("Unsupported OpenAPI: " + name);
+ }
+
+ String url = schema.getUrl();
+ if (StringUtils.isNoneBlank(baseUrl)) {
+ url = baseUrl + url;
+ }
+ CURLBuilder curlBuilder = new CURLBuilder(url);
+ curlBuilder
+ .addHeader("Content-Type", "application/x-www-form-urlencoded;
charset=UTF-8")
+ .addHeader(
+ "Authorization",
accessTokenService.getByUserId(serviceHelper.getUserId()).getToken());
+
+ schema
+ .getSchema()
+ .forEach(
+ c -> {
+ if (c.isRequired()) {
+ if ("appId".equals(c.getBindFor())) {
+ curlBuilder.addFormData(c.getName(), appId);
+ } else if ("teamId".equals(c.getBindFor())) {
+ curlBuilder.addFormData(c.getName(), teamId);
+ }
+ } else {
+ curlBuilder.addFormData(c.getName(), c.getDefaultValue());
+ }
+ });
+ return curlBuilder.build();
+ }
+
+ private void initOpenAPISchema() {
+ initTypes();
+ Class<?> clazz = OpenAPIController.class;
+ RequestMapping requestMapping =
clazz.getDeclaredAnnotation(RequestMapping.class);
+ String basePath = requestMapping.value()[0];
+ List<Method> methodList = ReflectUtils.getMethodsByAnnotation(clazz,
OpenAPI.class);
+
+ for (Method method : methodList) {
+ OpenAPISchema detail = new OpenAPISchema();
+
+ List<OpenAPISchema.Schema> headerList = new ArrayList<>();
+ OpenAPI openAPI = method.getDeclaredAnnotation(OpenAPI.class);
+ for (OpenAPI.Param header : openAPI.header()) {
+ headerList.add(paramToSchema(header));
+ }
+
+ List<OpenAPISchema.Schema> paramList = new ArrayList<>();
+ for (OpenAPI.Param param : openAPI.param()) {
+ paramList.add(paramToSchema(param));
+ }
+
+ detail.setSchema(paramList);
+ detail.setHeader(headerList);
+
+ Tuple2<String, String[]> methodURI = getMethodAndRequestURI(method);
+ String[] requestURI = methodURI.t2;
+ String uri = (requestURI != null && requestURI.length > 0) ?
requestURI[0] : "";
+ String restURI = "/" + basePath;
+ if (uri != null) {
+ restURI += "/" + uri;
+ }
+ restURI = restURI.replaceAll("/+", "/").replaceAll("/$", "");
+ detail.setUrl(restURI);
+ detail.setMethod(methodURI.t1);
+ schemas.put(openAPI.name(), detail);
+ }
+ }
+
+ private OpenAPISchema.Schema paramToSchema(OpenAPI.Param param) {
+ OpenAPISchema.Schema schema = new OpenAPISchema.Schema();
+ schema.setName(param.name());
+ if (StringUtils.isBlank(param.bindFor())) {
+ schema.setBindFor(param.name());
+ } else {
+ schema.setBindFor(param.bindFor());
+ }
+ schema.setRequired(param.required());
+ schema.setDescription(param.description());
+ schema.setDefaultValue(param.defaultValue());
+ String type = types.get(param.type().getSimpleName());
+ if (type != null) {
+ schema.setType(type);
+ } else {
+ schema.setType("string(" + param.type().getSimpleName() + ")");
+ }
+ return schema;
+ }
+
+ private Tuple2<String, String[]> getMethodAndRequestURI(Method method) {
+ method.setAccessible(true);
+
+ GetMapping getMapping = method.getDeclaredAnnotation(GetMapping.class);
+ if (getMapping != null) {
+ return Tuple2.of(HttpMethod.GET.name(), getMapping.value());
+ }
+
+ PostMapping postMapping = method.getDeclaredAnnotation(PostMapping.class);
+ if (postMapping != null) {
+ return Tuple2.of(HttpMethod.POST.name(), postMapping.value());
+ }
+
+ DeleteMapping deleteMapping =
method.getDeclaredAnnotation(DeleteMapping.class);
+ if (deleteMapping != null) {
+ return Tuple2.of(HttpMethod.DELETE.name(), deleteMapping.value());
+ }
+
+ PatchMapping patchMapping =
method.getDeclaredAnnotation(PatchMapping.class);
+ if (patchMapping != null) {
+ return Tuple2.of(HttpMethod.PATCH.name(), patchMapping.value());
+ }
+
+ PutMapping putMapping = method.getDeclaredAnnotation(PutMapping.class);
+ if (putMapping != null) {
+ return Tuple2.of(HttpMethod.PUT.name(), putMapping.value());
+ }
+
+ throw new IllegalArgumentException(
+ "get http method and requestURI failed: " + method.getName());
+ }
+
+ private void initTypes() {
+ types.put("String", "string");
+
+ types.put("int", "integer(int32)");
+ types.put("Integer", "integer(int32)");
+ types.put("Short", "integer(int32)");
+
+ types.put("long", "integer(int64)");
+ types.put("Long", "integer(int64)");
+
+ types.put("double", "number(double)");
+ types.put("Double", "number(double)");
+
+ types.put("float", "number(float)");
+ types.put("Float", "number(float)");
+ types.put("boolean", "boolean");
+ types.put("Boolean", "boolean");
+
+ types.put("byte", "string(byte)");
+ types.put("Byte", "string(byte)");
+
+ types.put("Date", "string(date)");
+ types.put("DateTime", "string(datetime)");
+ }
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
index b2e6ace9e..411473a3f 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
@@ -22,7 +22,6 @@ import org.apache.streampark.common.util.YarnUtils;
import org.apache.streampark.console.base.domain.RestRequest;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.InternalException;
-import org.apache.streampark.console.core.annotation.ApiAccess;
import org.apache.streampark.console.core.annotation.AppUpdated;
import org.apache.streampark.console.core.annotation.PermissionScope;
import org.apache.streampark.console.core.entity.Application;
@@ -141,7 +140,6 @@ public class ApplicationController {
return RestResponse.success(stateEnum.get());
}
- @ApiAccess
@PermissionScope(app = "#app.id", team = "#app.teamId")
@PostMapping(value = "start")
@RequiresPermissions("app:start")
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
new file mode 100644
index 000000000..613d8c379
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.core.annotation.OpenAPI;
+import org.apache.streampark.console.core.annotation.PermissionScope;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+import org.apache.streampark.console.core.component.OpenAPIComponent;
+import org.apache.streampark.console.core.entity.Application;
+import org.apache.streampark.console.core.service.ApplicationService;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.NotBlank;
+
+@Validated
+@RestController
+@RequestMapping("openapi")
+public class OpenAPIController {
+
+ @Autowired private OpenAPIComponent openAPIComponent;
+
+ @Autowired private ApplicationService applicationService;
+
+ @OpenAPI(
+ name = "flinkStart",
+ header = {
+ @OpenAPI.Param(
+ name = "Authorization",
+ description = "Access authorization token",
+ required = true,
+ type = String.class)
+ },
+ param = {
+ @OpenAPI.Param(
+ name = "id",
+ description = "current flink application id",
+ required = true,
+ type = Long.class,
+ bindFor = "appId"),
+ @OpenAPI.Param(
+ name = "teamId",
+ description = "current user teamId",
+ required = true,
+ type = Long.class),
+ @OpenAPI.Param(
+ name = "savePointed",
+ description = "restored app from the savepoint or latest
checkpoint",
+ required = false,
+ type = String.class,
+ defaultValue = "false"),
+ @OpenAPI.Param(
+ name = "savePoint",
+ description = "savepoint or checkpoint path",
+ required = false,
+ type = String.class),
+ @OpenAPI.Param(
+ name = "allowNonRestored",
+ description = "ignore savepoint if cannot be restored",
+ required = false,
+ type = boolean.class,
+ defaultValue = "false")
+ })
+ @PermissionScope(app = "#app.appId", team = "#app.teamId")
+ @PostMapping("app/start")
+ @RequiresPermissions("app:start")
+ public RestResponse flinkStart(Application app) throws Exception {
+ applicationService.start(app, false);
+ return RestResponse.success(true);
+ }
+
+ @OpenAPI(
+ name = "flinkCancel",
+ header = {
+ @OpenAPI.Param(
+ name = "Authorization",
+ description = "Access authorization token",
+ required = true,
+ type = String.class)
+ },
+ param = {
+ @OpenAPI.Param(
+ name = "id",
+ description = "current flink application id",
+ required = true,
+ type = Long.class,
+ bindFor = "appId"),
+ @OpenAPI.Param(
+ name = "teamId",
+ description = "current user teamId",
+ required = true,
+ type = Long.class),
+ @OpenAPI.Param(
+ name = "savePointed",
+ description = "trigger savepoint before taking stopping",
+ required = false,
+ type = boolean.class,
+ defaultValue = "false"),
+ @OpenAPI.Param(
+ name = "savePoint",
+ description = "savepoint path",
+ required = false,
+ type = String.class),
+ @OpenAPI.Param(
+ name = "drain",
+ description = "send max watermark before canceling",
+ required = false,
+ type = boolean.class,
+ defaultValue = "false"),
+ })
+ @PermissionScope(app = "#app.appId", team = "#app.teamId")
+ @PostMapping("app/cancel")
+ @RequiresPermissions("app:cancel")
+ public RestResponse flinkCancel(Application app) throws Exception {
+ applicationService.cancel(app);
+ return RestResponse.success();
+ }
+
+ @PostMapping("curl")
+ public RestResponse copyOpenApiCurl(
+ String baseUrl,
+ Long appId,
+ @NotBlank(message = "{required}") Long teamId,
+ @NotBlank(message = "{required}") String name) {
+ String url = openAPIComponent.getOpenApiCUrl(baseUrl, appId, teamId, name);
+ return RestResponse.success(url);
+ }
+
+ @PostMapping("schema")
+ public RestResponse schema(@NotBlank(message = "{required}") String name) {
+ OpenAPISchema openAPISchema = openAPIComponent.getOpenAPISchema(name);
+ return RestResponse.success(openAPISchema);
+ }
+}