/*
* 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 2005 - 2009 Pentaho Corporation. All rights reserved.
*
*
* @created Sep 12, 2005
* @author James Dixon
*/
package org.pentaho.platform.plugin.services.connections.javascript;
import java.text.SimpleDateFormat;
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;
public class JavaScriptResultSet extends ScriptableObject implements IPentahoResultSet, IPeekable {
/**
*
*/
private static final long serialVersionUID = -2303805979176976941L;
private IPentahoResultSet results;
private MemoryResultSet writeableResults;
protected Object peekRow[];
// private IPentahoMetaData metaData;
// private List rows;
// private Iterator iterator = null;
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);
}
}