2017-07-25 19:10:31 +08:00
|
|
|
/*
|
|
|
|
|
* Copyright 2017 HugeGraph Authors
|
|
|
|
|
*
|
|
|
|
|
* 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
|
2017-08-16 16:13:20 +08:00
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
2017-07-25 19:10:31 +08:00
|
|
|
*/
|
2017-08-17 16:26:01 +08:00
|
|
|
|
2017-05-17 21:16:40 +08:00
|
|
|
package com.baidu.hugegraph.api;
|
|
|
|
|
|
2017-12-04 14:32:35 +08:00
|
|
|
import java.util.Collection;
|
2017-11-01 12:09:21 +08:00
|
|
|
import java.util.Iterator;
|
2017-05-18 16:29:08 +08:00
|
|
|
import java.util.Map;
|
2017-12-19 20:46:26 +08:00
|
|
|
import java.util.concurrent.Callable;
|
2018-01-04 16:18:40 +08:00
|
|
|
import java.util.function.Consumer;
|
2017-05-18 16:29:08 +08:00
|
|
|
|
2017-05-17 21:16:40 +08:00
|
|
|
import javax.ws.rs.NotFoundException;
|
2017-12-04 14:32:35 +08:00
|
|
|
import javax.ws.rs.NotSupportedException;
|
2017-08-28 21:18:53 +08:00
|
|
|
import javax.ws.rs.core.MediaType;
|
2017-05-17 21:16:40 +08:00
|
|
|
|
2020-03-13 13:57:55 +08:00
|
|
|
import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
|
2017-12-19 20:46:26 +08:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
|
2020-04-23 17:14:22 +08:00
|
|
|
import com.baidu.hugegraph.GremlinGraph;
|
2017-12-19 20:46:26 +08:00
|
|
|
import com.baidu.hugegraph.HugeException;
|
2017-12-06 16:15:20 +08:00
|
|
|
import com.baidu.hugegraph.HugeGraph;
|
2020-04-23 17:14:22 +08:00
|
|
|
import com.baidu.hugegraph.auth.HugePermission;
|
2017-05-17 21:16:40 +08:00
|
|
|
import com.baidu.hugegraph.core.GraphManager;
|
2019-09-02 14:25:28 +08:00
|
|
|
import com.baidu.hugegraph.define.Checkable;
|
2019-05-31 17:06:40 +08:00
|
|
|
import com.baidu.hugegraph.metrics.MetricsUtil;
|
2017-12-19 20:46:26 +08:00
|
|
|
import com.baidu.hugegraph.server.RestServer;
|
2017-11-03 21:14:21 +08:00
|
|
|
import com.baidu.hugegraph.type.HugeType;
|
2017-12-04 14:32:35 +08:00
|
|
|
import com.baidu.hugegraph.util.E;
|
2019-11-27 19:15:23 +08:00
|
|
|
import com.baidu.hugegraph.util.JsonUtil;
|
2017-12-19 20:46:26 +08:00
|
|
|
import com.baidu.hugegraph.util.Log;
|
2018-05-28 22:24:57 +08:00
|
|
|
import com.codahale.metrics.Meter;
|
2017-11-03 21:14:21 +08:00
|
|
|
import com.google.common.collect.ImmutableMap;
|
2017-05-17 21:16:40 +08:00
|
|
|
|
|
|
|
|
public class API {
|
|
|
|
|
|
2017-12-19 20:46:26 +08:00
|
|
|
private static final Logger LOG = Log.logger(RestServer.class);
|
|
|
|
|
|
2017-08-31 19:42:18 +08:00
|
|
|
public static final String CHARSET = "UTF-8";
|
|
|
|
|
|
2017-08-28 21:18:53 +08:00
|
|
|
public static final String APPLICATION_JSON = MediaType.APPLICATION_JSON;
|
2017-08-31 19:42:18 +08:00
|
|
|
public static final String APPLICATION_JSON_WITH_CHARSET =
|
2019-07-29 14:21:40 +08:00
|
|
|
APPLICATION_JSON + ";charset=" + CHARSET;
|
|
|
|
|
public static final String JSON = MediaType.APPLICATION_JSON_TYPE
|
|
|
|
|
.getSubtype();
|
2017-08-28 21:18:53 +08:00
|
|
|
|
2017-10-26 13:13:31 +08:00
|
|
|
public static final String ACTION_APPEND = "append";
|
|
|
|
|
public static final String ACTION_ELIMINATE = "eliminate";
|
|
|
|
|
|
2018-05-28 22:24:57 +08:00
|
|
|
private static final Meter succeedMeter =
|
|
|
|
|
MetricsUtil.registerMeter(API.class, "commit-succeed");
|
|
|
|
|
private static final Meter illegalArgErrorMeter =
|
|
|
|
|
MetricsUtil.registerMeter(API.class, "illegal-arg");
|
|
|
|
|
private static final Meter expectedErrorMeter =
|
|
|
|
|
MetricsUtil.registerMeter(API.class, "expected-error");
|
|
|
|
|
private static final Meter unknownErrorMeter =
|
|
|
|
|
MetricsUtil.registerMeter(API.class, "unknown-error");
|
|
|
|
|
|
2020-04-23 17:14:22 +08:00
|
|
|
public static GremlinGraph graph(GraphManager manager, String graph) {
|
|
|
|
|
GremlinGraph g = manager.graph(graph);
|
2017-05-17 21:16:40 +08:00
|
|
|
if (g == null) {
|
2017-12-27 16:17:40 +08:00
|
|
|
throw new NotFoundException(String.format(
|
|
|
|
|
"Graph '%s' does not exist", graph));
|
2017-05-17 21:16:40 +08:00
|
|
|
}
|
|
|
|
|
return g;
|
|
|
|
|
}
|
2017-05-18 16:29:08 +08:00
|
|
|
|
2020-04-23 17:14:22 +08:00
|
|
|
public static HugeGraph graph4schema(GremlinGraph g) {
|
|
|
|
|
return g.hugegraph(HugePermission.SCHEMA_READ.string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4gremlin(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.GREMLIN.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4vertex(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.VERTEX_READ.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4edge(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.EDGE_READ.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4path(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.PATH_READ.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4taskr(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.TASK_READ.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4taskw(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.TASK_WRITE.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4taskd(GraphManager manager, String graph) {
|
|
|
|
|
String permission = HugePermission.TASK_DELETE.string();
|
|
|
|
|
return graph(manager, graph).hugegraph(permission);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static HugeGraph graph4admin(GraphManager manager, String graph) {
|
|
|
|
|
return graph(manager, graph).hugegraph();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static <R> R commit(GremlinGraph g, Callable<R> callable) {
|
2018-01-04 16:18:40 +08:00
|
|
|
Consumer<Throwable> rollback = (error) -> {
|
2018-03-16 15:41:53 +08:00
|
|
|
if (error != null) {
|
|
|
|
|
LOG.error("Failed to commit", error);
|
|
|
|
|
}
|
2018-01-04 16:18:40 +08:00
|
|
|
try {
|
|
|
|
|
g.tx().rollback();
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
LOG.error("Failed to rollback", e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-12-19 20:46:26 +08:00
|
|
|
try {
|
|
|
|
|
R result = callable.call();
|
|
|
|
|
g.tx().commit();
|
2018-05-28 22:24:57 +08:00
|
|
|
succeedMeter.mark();
|
2017-12-19 20:46:26 +08:00
|
|
|
return result;
|
2018-07-06 15:04:27 +08:00
|
|
|
} catch (IllegalArgumentException | NotFoundException e) {
|
2018-05-28 22:24:57 +08:00
|
|
|
illegalArgErrorMeter.mark();
|
2018-03-16 15:41:53 +08:00
|
|
|
rollback.accept(null);
|
|
|
|
|
throw e;
|
2018-01-04 16:18:40 +08:00
|
|
|
} catch (RuntimeException e) {
|
2018-05-28 22:24:57 +08:00
|
|
|
expectedErrorMeter.mark();
|
2018-01-04 16:18:40 +08:00
|
|
|
rollback.accept(e);
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Throwable e) {
|
2018-05-28 22:24:57 +08:00
|
|
|
unknownErrorMeter.mark();
|
2018-01-04 16:18:40 +08:00
|
|
|
rollback.accept(e);
|
|
|
|
|
// TODO: throw the origin exception 'e'
|
|
|
|
|
throw new HugeException("Failed to commit", e);
|
2017-12-19 20:46:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-23 17:14:22 +08:00
|
|
|
public static void commit(GremlinGraph g, Runnable runnable) {
|
2017-12-19 20:46:26 +08:00
|
|
|
commit(g, () -> {
|
|
|
|
|
runnable.run();
|
|
|
|
|
return null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 21:21:01 +08:00
|
|
|
public static Object[] properties(Map<String, Object> properties) {
|
2017-05-18 16:29:08 +08:00
|
|
|
Object[] list = new Object[properties.size() * 2];
|
|
|
|
|
int i = 0;
|
2017-05-19 21:21:01 +08:00
|
|
|
for (Map.Entry<String, Object> prop : properties.entrySet()) {
|
2017-05-18 16:29:08 +08:00
|
|
|
list[i++] = prop.getKey();
|
|
|
|
|
list[i++] = prop.getValue();
|
|
|
|
|
}
|
|
|
|
|
return list;
|
|
|
|
|
}
|
2017-11-01 12:09:21 +08:00
|
|
|
|
2017-12-04 14:32:35 +08:00
|
|
|
protected static void checkExist(Iterator<?> iter,
|
|
|
|
|
HugeType type,
|
|
|
|
|
String id) {
|
2017-11-01 12:09:21 +08:00
|
|
|
if (!iter.hasNext()) {
|
2020-03-13 13:57:55 +08:00
|
|
|
try {
|
|
|
|
|
CloseableIterator.closeIterator(iter);
|
|
|
|
|
} catch (Exception ignored) {}
|
|
|
|
|
|
2017-12-27 16:17:40 +08:00
|
|
|
throw new NotFoundException(String.format(
|
2019-06-03 18:05:23 +08:00
|
|
|
"%s with id '%s' does not exist",
|
|
|
|
|
type.readableName(), id));
|
2017-11-01 12:09:21 +08:00
|
|
|
}
|
|
|
|
|
}
|
2017-11-03 21:14:21 +08:00
|
|
|
|
2018-01-11 21:04:11 +08:00
|
|
|
protected static void checkCreatingBody(Checkable body) {
|
2017-12-04 14:32:35 +08:00
|
|
|
E.checkArgumentNotNull(body, "The request body can't be empty");
|
2018-01-11 21:04:11 +08:00
|
|
|
body.checkCreate(false);
|
2017-12-04 14:32:35 +08:00
|
|
|
}
|
|
|
|
|
|
2018-01-11 21:04:11 +08:00
|
|
|
protected static void checkUpdatingBody(Checkable body) {
|
|
|
|
|
E.checkArgumentNotNull(body, "The request body can't be empty");
|
|
|
|
|
body.checkUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-11 21:20:42 +08:00
|
|
|
protected static void checkCreatingBody(
|
|
|
|
|
Collection<? extends Checkable> bodys) {
|
2017-12-04 14:32:35 +08:00
|
|
|
E.checkArgumentNotNull(bodys, "The request body can't be empty");
|
2019-07-23 18:36:49 +08:00
|
|
|
for (Checkable body : bodys) {
|
|
|
|
|
E.checkArgument(body != null,
|
|
|
|
|
"The batch body can't contain null record");
|
|
|
|
|
body.checkCreate(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static void checkUpdatingBody(
|
|
|
|
|
Collection<? extends Checkable> bodys) {
|
|
|
|
|
E.checkArgumentNotNull(bodys, "The request body can't be empty");
|
2017-12-04 14:32:35 +08:00
|
|
|
for (Checkable body : bodys) {
|
2018-01-30 17:34:36 +08:00
|
|
|
E.checkArgumentNotNull(body,
|
|
|
|
|
"The batch body can't contain null record");
|
2019-07-23 18:36:49 +08:00
|
|
|
body.checkUpdate();
|
2017-12-04 14:32:35 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-03 21:14:21 +08:00
|
|
|
@SuppressWarnings("unchecked")
|
2017-12-04 14:32:35 +08:00
|
|
|
protected static Map<String, Object> parseProperties(String properties) {
|
2017-11-03 21:14:21 +08:00
|
|
|
if (properties == null || properties.isEmpty()) {
|
|
|
|
|
return ImmutableMap.of();
|
|
|
|
|
}
|
2019-11-27 19:15:23 +08:00
|
|
|
|
2017-11-03 21:14:21 +08:00
|
|
|
Map<String, Object> props = null;
|
|
|
|
|
try {
|
2019-11-27 19:15:23 +08:00
|
|
|
props = JsonUtil.fromJson(properties, Map.class);
|
2018-01-30 17:34:36 +08:00
|
|
|
} catch (Exception ignored) {}
|
2019-11-27 19:15:23 +08:00
|
|
|
|
2017-11-03 21:14:21 +08:00
|
|
|
// If properties is the string "null", props will be null
|
2019-11-27 19:15:23 +08:00
|
|
|
E.checkArgument(props != null,
|
|
|
|
|
"Invalid request with properties: %s", properties);
|
2017-11-03 21:14:21 +08:00
|
|
|
return props;
|
|
|
|
|
}
|
2017-12-04 14:32:35 +08:00
|
|
|
|
|
|
|
|
public static boolean checkAndParseAction(String action) {
|
|
|
|
|
E.checkArgumentNotNull(action, "The action param can't be empty");
|
|
|
|
|
if (action.equals(ACTION_APPEND)) {
|
|
|
|
|
return true;
|
|
|
|
|
} else if (action.equals(ACTION_ELIMINATE)) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
throw new NotSupportedException(
|
|
|
|
|
String.format("Not support action '%s'", action));
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-17 21:16:40 +08:00
|
|
|
}
|