Search code examples
pluginsgremlintinkerpopjanusgraphgremlin-server

How to use BindingsGremlinPlugin class for adding bindings to embedded gremlin-server?


I have initialized janus-graph instance in my app. I use FERMA OGM to interact with it. I also want to provide network access to it so I consider using of gremlin-server in embedded mode.

I do that in that way:

InputStream inputStream = getClass().getClassLoader().getResourceAsStream("gremlin-server-simple.yaml");        

Settings settings = Settings.read(inputStream);
settings.graphs.clear();

GremlinServer gremlinServer = new GremlinServer(settings);
GraphManager graphManager = gremlinServer.getServerGremlinExecutor().getGraphManager();
graphManager.putGraph("graph", jg);
// jg - graph instance
...
gremlinServer.start();

gremlin-server-simple.yaml:

host: localhost
port: 8182
scriptEvaluationTimeout: 30000
channelizer: org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer
graphManager: org.janusgraph.graphdb.management.JanusGraphManager

graphs: {}

scriptEngines: {
  gremlin-groovy: {
    plugins: { com.mallcloud.shortesttrack.metadata.commons.gremlin.ModJanusGraphJsrGremlinPlugin: {},
               org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: {},
               org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
               org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]}
               },
    imports: [java.lang.Math],
    staticImports: [java.lang.Math.PI],
    scripts: []}}

serializers:
  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}
  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
processors:
  - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}
  - { className: org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor, config: { cacheExpirationTime: 600000, cacheMaxSize: 1000 }}
metrics: {
  consoleReporter: {enabled: true, interval: 180000},
  csvReporter: {enabled: true, interval: 180000, fileName: /tmp/gremlin-server-metrics.csv},
  jmxReporter: {enabled: true},
  slf4jReporter: {enabled: true, interval: 180000},
  gangliaReporter: {enabled: false, interval: 180000, addressingMode: MULTICAST},
  graphiteReporter: {enabled: false, interval: 180000}}
maxInitialLineLength: 4096
maxHeaderSize: 8192
maxChunkSize: 8192
maxContentLength: 65536
maxAccumulationBufferComponents: 1024
resultIterationBatchSize: 64
writeBufferLowWaterMark: 32768
writeBufferHighWaterMark: 65536

But I can't define binding (g, graph) for my graph instance - jg. On this programmatically-add-global-variables-to-gremlin-server topic there was answer that It needs to use BindingsGremlinPlugin to add binding.

But I have no idea how to do it - should I add strings with that plugin class and binding in my gremlin-conf or I have to add binding from code (in some way)?


Update - in accordance to the answer I added bindings by modifying Settings instance:

InputStream inputStream = getClass().getClassLoader().getResourceAsStream(gremlinConfigFile);
Settings settings = Settings.read(inputStream);

// Create arg - bindingsMap
Map<String, Object> arg = new HashMap<>();
arg.put("graph", jg);
arg.put("g", jg.traversal());

// Create method2argMap
Map<String, Object> method2arg = new HashMap<>();
method2arg.put("bindings", arg);

// Add method2argMap to BindingsGremlinPlugin string
settings.scriptEngines.get("gremlin-groovy").plugins.put("org.apache.tinkerpop.gremlin.jsr223.BindingsGremlinPlugin", method2arg);

Solution

  • should I add strings with that plugin class and binding in my gremlin-conf or I have to add binding from code?

    I thnk that you have to use the Gremlin Server yaml file. Gremlin Server always looks to instantiate a plugin with a static instance() method or barring that, a static build() method that returns a Builder object. If it uses build() then it will use reflection to take any keys/values that you provide in a Map in the yaml file for that plugin and use the keys to reflect the names of methods on the Builder object and call them with the values as arguments. You must take care to match the expected data types for the Builder methods.

    So for BindingsGremlinPlugin you can see the build() method here which returns the Builder which is here and then that class has just one configuration method on it called bindings() which takes a Map. Therefore your configuration for such a class in the yaml must be:

    org.apache.tinkerpop.gremlin.jsr223.BindingsGremlinPlugin: {bindings: {x: 123}}
    

    which would put the variable "x" with the value "123" on the global bindings. Obviously, the limitation here is that you can only use types allowed by yaml. Note that you don't have to add the above to your yaml file as you are embedding and could programmatically update the Settings object to include it prior to handing it over to Gremlin Server to start it up.

    The only way to programmatically use the BindingsGremlinPlugin would be if you were initializing your own GremlinExecutor or GremlinScriptEngine instance, which isn't the case here.

    If you need more complex objects on the bindings you could write your own extension of BindingsGremlinPlugin which could dynamically instantiate those complex values. Then reference your own implementation in the yaml files.