/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.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 org.pentaho.di.core.util; import org.mozilla.javascript.Context; import org.pentaho.di.compatibility.Value; import org.pentaho.di.core.Const; import org.pentaho.di.core.exception.KettleValueException; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.xml.XMLHandler; import java.math.BigDecimal; import java.util.Date; /** * This class contains common code from {@linkplain org.pentaho.di.trans.steps.script.Script} and {@linkplain * org.pentaho.di.trans.steps .scriptvalues_mod.ScriptValuesMod} classes * * @author Andrey Khayrutdinov */ public class JavaScriptUtils { public static Object convertFromJs( Object value, int type, String fieldName ) throws KettleValueException { String classType = value.getClass().getName(); switch ( type ) { case ValueMetaInterface.TYPE_NUMBER: return jsToNumber( value, classType ); case ValueMetaInterface.TYPE_INTEGER: return jsToInteger( value, value.getClass() ); case ValueMetaInterface.TYPE_STRING: return jsToString( value, classType ); case ValueMetaInterface.TYPE_DATE: return jsToDate( value, classType ); case ValueMetaInterface.TYPE_BOOLEAN: return value; case ValueMetaInterface.TYPE_BIGNUMBER: return jsToBigNumber( value, classType ); case ValueMetaInterface.TYPE_BINARY: { return Context.jsToJava( value, byte[].class ); } case ValueMetaInterface.TYPE_NONE: { throw new RuntimeException( "No data output data type was specified for new field [" + fieldName + "]" ); } default: return Context.jsToJava( value, Object.class ); } } public static Number jsToNumber( Object value, String classType ) { if ( classType.equalsIgnoreCase( "org.mozilla.javascript.Undefined" ) ) { return null; } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeJavaObject" ) ) { try { // Is it a java Value class ? Value v = (Value) Context.jsToJava( value, Value.class ); return v.getNumber(); } catch ( Exception e ) { String string = Context.toString( value ); return Double.parseDouble( Const.trim( string ) ); } } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeNumber" ) ) { Number nb = Context.toNumber( value ); return nb.doubleValue(); } else { Number nb = (Number) value; return nb.doubleValue(); } } public static Long jsToInteger( Object value, Class clazz ) { if ( Number.class.isAssignableFrom( clazz ) ) { return ( (Number) value ).longValue(); } else { String classType = clazz.getName(); if ( classType.equalsIgnoreCase( "java.lang.String" ) ) { return ( new Long( (String) value ) ); } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.Undefined" ) ) { return null; } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeNumber" ) ) { Number nb = Context.toNumber( value ); return nb.longValue(); } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeJavaObject" ) ) { // Is it a Value? // try { Value v = (Value) Context.jsToJava( value, Value.class ); return v.getInteger(); } catch ( Exception e2 ) { String string = Context.toString( value ); return Long.parseLong( Const.trim( string ) ); } } else { return Long.parseLong( value.toString() ); } } } public static String jsToString( Object value, String classType ) { if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeJavaObject" ) || classType.equalsIgnoreCase( "org.mozilla.javascript.Undefined" ) ) { // Is it a java Value class ? try { Value v = (Value) Context.jsToJava( value, Value.class ); return v.toString(); } catch ( Exception ev ) { // convert to a string should work in most cases... // return Context.toString( value ); } } else { // A String perhaps? return Context.toString( value ); } } public static Date jsToDate( Object value, String classType ) throws KettleValueException { double dbl; if ( classType.equalsIgnoreCase( "org.mozilla.javascript.Undefined" ) ) { return null; } else { if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeDate" ) ) { dbl = Context.toNumber( value ); } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeJavaObject" ) || classType.equalsIgnoreCase( "java.util.Date" ) ) { // Is it a java Date() class ? try { Date dat = (Date) Context.jsToJava( value, java.util.Date.class ); dbl = dat.getTime(); } catch ( Exception e ) { // Is it a Value? // try { Value v = (Value) Context.jsToJava( value, Value.class ); return v.getDate(); } catch ( Exception e2 ) { try { String string = Context.toString( value ); return XMLHandler.stringToDate( string ); } catch ( Exception e3 ) { throw new KettleValueException( "Can't convert a string to a date" ); } } } } else if ( classType.equalsIgnoreCase( "java.lang.Double" ) ) { dbl = (Double) value; } else { String string = (String) Context.jsToJava( value, String.class ); dbl = Double.parseDouble( string ); } long lng = Math.round( dbl ); return new Date( lng ); } } public static BigDecimal jsToBigNumber( Object value, String classType ) { if ( classType.equalsIgnoreCase( "org.mozilla.javascript.Undefined" ) ) { return null; } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeNumber" ) ) { Number nb = Context.toNumber( value ); return new BigDecimal( nb.doubleValue() ); } else if ( classType.equalsIgnoreCase( "org.mozilla.javascript.NativeJavaObject" ) ) { // Is it a BigDecimal class ? try { return (BigDecimal) Context.jsToJava( value, BigDecimal.class ); } catch ( Exception e ) { try { Value v = (Value) Context.jsToJava( value, Value.class ); if ( !v.isNull() ) { return v.getBigNumber(); } else { return null; } } catch ( Exception e2 ) { String string = (String) Context.jsToJava( value, String.class ); return new BigDecimal( string ); } } } else if ( classType.equalsIgnoreCase( "java.lang.Byte" ) ) { return new BigDecimal( ( (Byte) value ).longValue() ); } else if ( classType.equalsIgnoreCase( "java.lang.Short" ) ) { return new BigDecimal( ( (Short) value ).longValue() ); } else if ( classType.equalsIgnoreCase( "java.lang.Integer" ) ) { return new BigDecimal( ( (Integer) value ).longValue() ); } else if ( classType.equalsIgnoreCase( "java.lang.Long" ) ) { return new BigDecimal( ( (Long) value ).longValue() ); } else if ( classType.equalsIgnoreCase( "java.lang.Double" ) ) { return new BigDecimal( ( (Double) value ).doubleValue() ); } else if ( classType.equalsIgnoreCase( "java.lang.String" ) ) { return new BigDecimal( ( new Long( (String) value ) ).longValue() ); } else { throw new RuntimeException( "JavaScript conversion to BigNumber not implemented for " + classType ); } } }