/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.services.connections.javascript; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.pentaho.commons.connection.IPeekable; import org.pentaho.commons.connection.IPentahoMetaData; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.commons.connection.memory.MemoryMetaData; import org.pentaho.commons.connection.memory.MemoryResultSet; import java.text.SimpleDateFormat; public class JavaScriptResultSet extends ScriptableObject implements IPentahoResultSet, IPeekable { /** * */ private static final long serialVersionUID = -2303805979176976941L; private IPentahoResultSet results; private MemoryResultSet writeableResults; protected Object[] peekRow; private StringBuffer description; public JavaScriptResultSet() { description = new StringBuffer(); results = null; } public void setResultSet( final IPentahoResultSet pResults ) { this.results = pResults; if ( results instanceof MemoryResultSet ) { writeableResults = (MemoryResultSet) results; } } @Override public String getClassName() { return "JavaScriptResultSet"; //$NON-NLS-1$ } public static Object jsFunction_getColumnCount( final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj ) { if ( ( args != null ) && ( args.length > 0 ) ) { return null; } JavaScriptResultSet resultSet = (JavaScriptResultSet) thisObj; return new Integer( resultSet.getColumnCount() ); } public static Object jsFunction_getRowCount( final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj ) { if ( ( args != null ) && ( args.length > 0 ) ) { return null; } JavaScriptResultSet resultSet = (JavaScriptResultSet) thisObj; return new Integer( resultSet.getRowCount() ); } public static Object jsFunction_getValueAt( final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj ) { if ( args == null ) { return null; } if ( args.length < 2 ) { return null; } JavaScriptResultSet resultSet = (JavaScriptResultSet) thisObj; int row = 0, column = 0; try { if ( args[0] instanceof Number ) { row = ( (Number) args[0] ).intValue(); } else if ( args[0] instanceof String ) { row = Integer.parseInt( (String) args[0] ); } else { return null; } if ( args[1] instanceof Number ) { column = ( (Number) args[1] ).intValue(); } else if ( args[1] instanceof String ) { column = Integer.parseInt( (String) args[1] ); } else { return null; } } catch ( Exception e ) { return null; } return resultSet.getValueAt( row, column ); } public static Object jsFunction_setColumnHeaders( final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj ) { if ( args == null ) { return null; } if ( args.length == 0 ) { return null; } JavaScriptResultSet resultSet = (JavaScriptResultSet) thisObj; if ( ( args.length == 1 ) && ( args[0] instanceof NativeArray ) ) { NativeArray array = (NativeArray) args[0]; resultSet.setMetaData( JavaScriptResultSet.createMetadata( array, thisObj ) ); } else if ( ( args.length == 2 ) && ( args[0] instanceof NativeArray ) && ( args[1] instanceof NativeArray ) ) { NativeArray array = (NativeArray) args[0]; MemoryMetaData metaData = JavaScriptResultSet.createMetadata( array, thisObj ); // create some metadata objects array = (NativeArray) args[1]; int length = (int) array.getLength(); String[] columnTypes = new String[length]; for ( int i = 0; i < length; i++ ) { columnTypes[i] = array.get( i, thisObj ).toString(); } metaData.setColumnTypes( columnTypes ); resultSet.setMetaData( metaData ); } else { int length = args.length; String[] columnHeaders = new String[length]; for ( int i = 0; i < length; i++ ) { columnHeaders[i] = args[i].toString(); } MemoryMetaData metaData = new MemoryMetaData( new String[][] { columnHeaders }, null ); resultSet.setMetaData( metaData ); } return null; } private static MemoryMetaData createMetadata( final NativeArray array, final Scriptable thisObj ) { int length = (int) array.getLength(); String[] columnHeaders = new String[length]; for ( int i = 0; i < length; i++ ) { columnHeaders[i] = array.get( i, thisObj ).toString(); } return new MemoryMetaData( new String[][] { columnHeaders }, null ); } public static Object jsFunction_addRow( final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj ) { if ( args == null ) { return null; } if ( args.length == 0 ) { return null; } // TODO support dates JavaScriptResultSet resultSet = (JavaScriptResultSet) thisObj; if ( ( args.length == 1 ) && ( args[0] instanceof NativeArray ) ) { NativeArray array = (NativeArray) args[0]; int length = (int) array.getLength(); Object[] row = new Object[length]; String[] columnTypes = ( (MemoryMetaData) resultSet.getMetaData() ).getColumnTypes(); for ( int i = 0; i < length; i++ ) { Object data = array.get( i, thisObj ); if ( data == null ) { row[i] = null; } else if ( columnTypes != null ) { if ( data instanceof NativeJavaObject ) { // see if we can force a conversion Object outputClass = null; if ( "string".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ outputClass = java.lang.String.class; } else if ( "date".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ outputClass = java.util.Date.class; } else if ( "int".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ outputClass = java.lang.Integer.class; } else if ( "float".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ outputClass = java.lang.Float.class; } else if ( "double".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ outputClass = java.lang.Double.class; } if ( ( NativeJavaObject.canConvert( data, outputClass.getClass() ) ) ) { row[i] = Context.jsToJava( data, java.lang.String.class ); } else { row[i] = null; } } if ( "string".equalsIgnoreCase( columnTypes[i] ) ) { //$NON-NLS-1$ row[i] = data.toString(); } else if ( "date".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof String ) ) { //$NON-NLS-1$ SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" ); //$NON-NLS-1$ try { row[i] = format.parse( (String) data ); } catch ( Throwable t ) { row[i] = null; } } else if ( "int".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof Integer ) ) { //$NON-NLS-1$ row[i] = data; } else if ( "int".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof Double ) ) { //$NON-NLS-1$ row[i] = new Integer( ( (Double) data ).intValue() ); } else if ( "int".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof String ) ) { //$NON-NLS-1$ row[i] = new Integer( (String) data ); } else if ( "float".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof Double ) ) { //$NON-NLS-1$ row[i] = data; } else if ( "float".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof Integer ) ) { //$NON-NLS-1$ row[i] = new Double( ( (Integer) data ).floatValue() ); } else if ( "float".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof String ) ) { //$NON-NLS-1$ row[i] = new Integer( (String) data ); } else if ( "double".equalsIgnoreCase( columnTypes[i] ) && ( data instanceof Double ) ) { //$NON-NLS-1$ row[i] = data; } } else if ( data instanceof NativeJavaObject ) { Object obj = ( (NativeJavaObject) data ).unwrap(); row[i] = obj; } else { row[i] = data; } } resultSet.addRow( row ); } else { int length = args.length; String[] row = new String[length]; for ( int i = 0; i < length; i++ ) { row[i] = args[i].toString(); } resultSet.addRow( row ); } return null; } public void setMetaData( final IPentahoMetaData metaData ) { results = new MemoryResultSet( metaData ); writeableResults = (MemoryResultSet) results; // this.metaData = metaData; // rows = new ArrayList(); } /* IPentahoResultSet methods */ public void addRow( final String[] row ) { if ( writeableResults != null ) { writeableResults.addRow( row ); } // rows.add( row ); if ( description.length() < 100 ) { description.append( row ); } } public void addRow( final Object[] row ) { if ( writeableResults != null ) { writeableResults.addRow( row ); } // rows.add( row ); if ( description.length() < 100 ) { description.append( row ); } } @Override public String toString() { if ( results.getMetaData().getColumnHeaders() != null ) { return results.getMetaData().getColumnHeaders().toString() + description.toString(); } return description.toString(); } public IPentahoMetaData getMetaData() { return results.getMetaData(); } public Object[] peek() { if ( peekRow == null ) { peekRow = next(); } return peekRow; } public Object[] next() { if ( peekRow != null ) { Object[] row = peekRow; peekRow = null; return row; } return results.next(); } public void close() { // dispose of the iterator so the rows can be iterated again results.close(); } public void closeConnection() { close(); } public void dispose() { close(); } public boolean isScrollable() { return true; } public int getColumnCount() { return results.getMetaData().getColumnCount(); } public int getRowCount() { return results.getRowCount(); } public Object getValueAt( final int row, final int column ) { return results.getValueAt( row, column ); } public IPentahoResultSet memoryCopy() { return results.memoryCopy(); } public void beforeFirst() { results.beforeFirst(); } public Object[] getDataColumn( final int column ) { return results.getDataColumn( column ); } public Object[] getDataRow( final int row ) { return results.getDataRow( row ); } }