| /* |
| * 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.tinkerpop.gremlin.python.jsr223; |
| |
| import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator; |
| import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineCache; |
| import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; |
| import org.apache.tinkerpop.gremlin.process.traversal.Translator; |
| import org.apache.tinkerpop.gremlin.process.traversal.Traversal; |
| import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; |
| import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONReader; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0; |
| import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3d0; |
| import org.apache.tinkerpop.shaded.jackson.core.JsonFactory; |
| import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper; |
| |
| import javax.script.Bindings; |
| import javax.script.ScriptContext; |
| import javax.script.ScriptEngine; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.util.Map; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| /** |
| * @author Marko A. Rodriguez (http://markorodriguez.com) |
| */ |
| final class PythonGraphSONJavaTranslator<S extends TraversalSource, T extends Traversal.Admin<?, ?>> implements Translator.StepTranslator<S, T> { |
| |
| private final boolean IS_TESTING = Boolean.valueOf(System.getProperty("is.testing", "false")); |
| private final PythonTranslator pythonTranslator; |
| private final JavaTranslator<S, T> javaTranslator; |
| private final GraphSONReader reader; |
| private final GraphSONWriter writer; |
| private final GraphSONVersion version; |
| |
| public PythonGraphSONJavaTranslator(final PythonTranslator pythonTranslator, final JavaTranslator<S, T> javaTranslator, final GraphSONVersion version) { |
| this.pythonTranslator = pythonTranslator; |
| this.javaTranslator = javaTranslator; |
| this.version = version; |
| this.reader = GraphSONReader.build().mapper( |
| GraphSONMapper.build().addCustomModule(version.equals(GraphSONVersion.V2_0) ? |
| GraphSONXModuleV2d0.build().create(false) : |
| GraphSONXModuleV3d0.build().create(false)) |
| .version(version).create()).create(); |
| this.writer = GraphSONWriter.build().mapper( |
| GraphSONMapper.build().addCustomModule(version.equals(GraphSONVersion.V2_0) ? |
| GraphSONXModuleV2d0.build().create(false) : |
| GraphSONXModuleV3d0.build().create(false)) |
| .version(version).create()).create(); |
| } |
| |
| @Override |
| public S getTraversalSource() { |
| return this.javaTranslator.getTraversalSource(); |
| } |
| |
| @Override |
| public String getTargetLanguage() { |
| return this.javaTranslator.getTargetLanguage(); |
| } |
| |
| @Override |
| public T translate(final Bytecode bytecode) { |
| try { |
| final ScriptEngine jythonEngine = ScriptEngineCache.get("jython"); |
| final Bindings bindings = jythonEngine.createBindings(); |
| bindings.putAll(jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE)); |
| bindings.put(this.pythonTranslator.getTraversalSource(), jythonEngine.eval("Graph().traversal()")); |
| bindings.putAll(bytecode.getBindings()); |
| final String translatedGraphSONBytecode = jythonEngine.eval((this.version.equals(GraphSONVersion.V2_0) ? |
| "graphsonV2d0_writer" : |
| "graphsonV3d0_writer") + |
| ".writeObject(" + this.pythonTranslator.translate(bytecode) + ")", bindings).toString(); |
| if (IS_TESTING) { |
| // verify that the GraphSON sent to Python is the same as the GraphSON returned by Python |
| final ByteArrayOutputStream output = new ByteArrayOutputStream(); |
| BytecodeHelper.removeBindings(bytecode); // this is because bindings are variables that get converted to values at translation |
| BytecodeHelper.detachElements(bytecode); // this is to get the minimal necessary representation |
| this.writer.writeObject(output, bytecode); |
| final String originalGraphSONBytecode = new String(output.toByteArray()); |
| final ObjectMapper mapper = new ObjectMapper(new JsonFactory()); |
| // System.out.println(originalGraphSONBytecode + "\n" + translatedGraphSONBytecode + "\n\n"); |
| final Map<String, Object> original = mapper.readValue(originalGraphSONBytecode, Map.class); |
| final Map<String, Object> translated = mapper.readValue(translatedGraphSONBytecode, Map.class); |
| assertEquals(originalGraphSONBytecode.length(), translatedGraphSONBytecode.length()); |
| assertEquals(original, translated); |
| } |
| return this.javaTranslator.translate(this.reader.readObject(new ByteArrayInputStream(translatedGraphSONBytecode.getBytes()), Bytecode.class)); |
| |
| } catch (final Exception e) { |
| throw new IllegalArgumentException(e.getMessage(), e); |
| } |
| |
| } |
| } |