/* * Copyright (c) 2014. * * BaasBox - info@baasbox.com * * Licensed 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 com.baasbox.service.scripting.js; import com.baasbox.dao.exception.ScriptException; import com.baasbox.service.scripting.base.ScriptEvalException; import com.baasbox.service.scripting.base.ScriptResult; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.*; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.api.scripting.ScriptUtils; import jdk.nashorn.internal.runtime.Undefined; import com.baasbox.service.logging.BaasBoxLogger; import scala.util.parsing.combinator.testing.Str; import java.io.IOException; import java.util.Collection; import java.util.Map; import java.util.Set; /** * This implements mappings of data to/from javascript * Created by Andrea Tortorella on 30/06/14. */ final class NashornMapper { private final static String JSON_PARSE = "asJson"; private final static String EVENT_NAME="name"; private final static String EVENT_DATA="data"; private ScriptObjectMirror mirror; NashornMapper(){ } void setMirror(ScriptObjectMirror mirror) { this.mirror = mirror; } Object convertEvent(String event, Object eventData) throws ScriptEvalException{ // todo add support for all dataTypes String eventJson; if (eventData == null) { eventJson = simpleEvent(event); } else if (eventData instanceof String) { eventJson = stringEvent(event,(String)eventData); } else if (eventData instanceof Integer || eventData instanceof Long || eventData instanceof Double || eventData instanceof Float){ eventJson = primitiveEvent(event,(Number)eventData); } else if (eventData instanceof Boolean) { eventJson = primitiveEvent(event,(Boolean)eventData); } else if (eventData instanceof JsonNode) { eventJson = objectEvent(event, (JsonNode) eventData); } else { throw new ScriptEvalException("Unsupported event data "+eventData.getClass()); } return convertToJSJson(eventJson); } private static String stringEvent(String event,String data){ ObjectNode node = Json.mapper().createObjectNode(); node.put(EVENT_NAME,event); node.put(EVENT_DATA,data); return node.toString(); } private static String simpleEvent(String event){ ObjectNode node = Json.mapper().createObjectNode(); node.put(EVENT_NAME,event); return node.toString(); } private static String primitiveEvent(String event,Number data){ ObjectNode node = Json.mapper().createObjectNode(); node.put(EVENT_NAME,event); node.put(EVENT_DATA,data.doubleValue()); return node.toString(); } private static String primitiveEvent(String event,Boolean data) { ObjectNode node = Json.mapper().createObjectNode(); node.put(EVENT_NAME,event); node.put(EVENT_DATA,data); return node.toString(); } private static String objectEvent(String event,JsonNode data) { ObjectNode node = Json.mapper().createObjectNode(); node.put(EVENT_NAME,event); node.put(EVENT_DATA,data); return node.toString(); } private Object convertToJSJson(String data) { return mirror.callMember(JSON_PARSE,data); } public ScriptResult convertResult(Object result) throws ScriptEvalException { if (result == null){ return ScriptResult.NULL; } else if (result instanceof Boolean){ return (Boolean) result ?ScriptResult.TRUE:ScriptResult.FALSE; } else if (result instanceof String){ return new ScriptResult((String)result); } else if (result instanceof ScriptObjectMirror){ JsonNode node = convertDeepJson(result); if (node != null){ return new ScriptResult(node); } else { return ScriptResult.NULL; } } else if (result instanceof Number){ return new ScriptResult((Number)result); } else if (result instanceof Undefined){ return ScriptResult.NULL; } else { BaasBoxLogger.warn("Mirror: %s, of type: %s",result,result.getClass()); return ScriptResult.NULL; } } private JsonNode convertNumber(Number number){ if (number instanceof Long||number instanceof Integer){ return LongNode.valueOf(number.longValue()); } else if (number instanceof Double||number instanceof Float){ return DoubleNode.valueOf(number.doubleValue()); } else { return LongNode.valueOf(number.longValue()); } } private JsonNode convertDeepJson(Object obj) throws ScriptEvalException{ if (obj == null){ return NullNode.getInstance(); } else if (obj instanceof Boolean){ return BooleanNode.valueOf((Boolean) obj); } else if (obj instanceof Undefined){ return MissingNode.getInstance(); } else if (obj instanceof Number){ return convertNumber((Number)obj); } else if (obj instanceof String){ return TextNode.valueOf((String)obj); } else if (obj instanceof ScriptObjectMirror){ return convertMirror((ScriptObjectMirror)obj); } else { return MissingNode.getInstance(); } } private JsonNode convertMirror(ScriptObjectMirror mirror) throws ScriptEvalException{ if (mirror == null){ return NullNode.getInstance(); } else if (ScriptObjectMirror.isUndefined(mirror)){ return MissingNode.getInstance(); } else if (mirror.isFunction()){ return MissingNode.getInstance(); } else if (mirror.isArray()){ Collection<Object> values = mirror.values(); ArrayNode node = Json.mapper().createArrayNode(); for (Object o: values){ JsonNode e = convertDeepJson(o); if (e.isMissingNode()){ continue; } node.add(e); } return node; }else if(mirror.hasMember("toJSON")){ Object toJSON = mirror.callMember("toJSON"); return convertDeepJson(toJSON); } else { ObjectNode obj = Json.mapper().createObjectNode(); Set<Map.Entry<String, Object>> entries = mirror.entrySet(); for (Map.Entry<String,Object> e:entries){ Object obv = e.getValue(); JsonNode jsonNode = convertDeepJson(obv); if (jsonNode.isMissingNode()){ continue; } obj.put(e.getKey(),jsonNode); } return obj; } } }