/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 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; import java.math.BigDecimal; import java.util.Date; import org.pentaho.di.core.exception.KettlePluginException; import org.pentaho.di.core.exception.KettleValueException; import org.pentaho.di.core.injection.InjectionTypeConverter; import org.pentaho.di.core.row.RowDataUtil; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.row.value.ValueMetaFactory; import org.pentaho.di.core.row.value.ValueMetaNone; import org.pentaho.di.repository.LongObjectId; import org.pentaho.di.repository.ObjectId; public class RowMetaAndData implements Cloneable { private RowMetaInterface rowMeta; private Object[] data; public RowMetaAndData() { clear(); } /** * @param rowMeta * @param data */ public RowMetaAndData( RowMetaInterface rowMeta, Object... data ) { this.rowMeta = rowMeta; this.data = data; } @Override public RowMetaAndData clone() { RowMetaAndData c = new RowMetaAndData(); c.rowMeta = rowMeta.clone(); try { c.data = rowMeta.cloneRow( data ); } catch ( KettleValueException e ) { throw new RuntimeException( "Problem with clone row detected in RowMetaAndData", e ); } return c; } @Override public String toString() { try { return rowMeta.getString( data ); } catch ( KettleValueException e ) { return rowMeta.toString() + ", error presenting data: " + e.toString(); } } /** * @return the data */ public Object[] getData() { return data; } /** * @param data * the data to set */ public void setData( Object[] data ) { this.data = data; } /** * @return the rowMeta */ public RowMetaInterface getRowMeta() { return rowMeta; } /** * @param rowMeta * the rowMeta to set */ public void setRowMeta( RowMetaInterface rowMeta ) { this.rowMeta = rowMeta; } @Override public int hashCode() { try { return rowMeta.hashCode( data ); } catch ( KettleValueException e ) { throw new RuntimeException( "Row metadata and data: unable to calculate hashcode because of a data conversion problem", e ); } } @Override public boolean equals( Object obj ) { try { return rowMeta.compare( data, ( (RowMetaAndData) obj ).getData() ) == 0; } catch ( KettleValueException e ) { throw new RuntimeException( "Row metadata and data: unable to compare rows because of a data conversion problem", e ); } } public void addValue( ValueMetaInterface valueMeta, Object valueData ) { if ( valueMeta.isInteger() && ( valueData instanceof ObjectId ) ) { valueData = new LongObjectId( (ObjectId) valueData ).longValue(); } data = RowDataUtil.addValueData( data, rowMeta.size(), valueData ); rowMeta.addValueMeta( valueMeta ); } public void addValue( String valueName, int valueType, Object valueData ) { ValueMetaInterface v; try { v = ValueMetaFactory.createValueMeta( valueName, valueType ); } catch ( KettlePluginException e ) { v = new ValueMetaNone( valueName ); } addValue( v, valueData ); } public void clear() { rowMeta = new RowMeta(); data = new Object[] {}; } public long getInteger( String valueName, long def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getInteger( idx, def ); } public long getInteger( int index, long def ) throws KettleValueException { Long number = rowMeta.getInteger( data, index ); if ( number == null ) { return def; } return number.longValue(); } public Long getInteger( String valueName ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return rowMeta.getInteger( data, idx ); } public Long getInteger( int index ) throws KettleValueException { return rowMeta.getInteger( data, index ); } public double getNumber( String valueName, double def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getNumber( idx, def ); } public double getNumber( int index, double def ) throws KettleValueException { Double number = rowMeta.getNumber( data, index ); if ( number == null ) { return def; } return number.doubleValue(); } public Date getDate( String valueName, Date def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getDate( idx, def ); } public Date getDate( int index, Date def ) throws KettleValueException { Date date = rowMeta.getDate( data, index ); if ( date == null ) { return def; } return date; } public BigDecimal getBigNumber( String valueName, BigDecimal def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getBigNumber( idx, def ); } public BigDecimal getBigNumber( int index, BigDecimal def ) throws KettleValueException { BigDecimal number = rowMeta.getBigNumber( data, index ); if ( number == null ) { return def; } return number; } public boolean getBoolean( String valueName, boolean def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getBoolean( idx, def ); } public boolean getBoolean( int index, boolean def ) throws KettleValueException { Boolean b = rowMeta.getBoolean( data, index ); if ( b == null ) { return def; } return b.booleanValue(); } public String getString( String valueName, String def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getString( idx, def ); } public String getString( int index, String def ) throws KettleValueException { String string = rowMeta.getString( data, index ); if ( string == null ) { return def; } return string; } public byte[] getBinary( String valueName, byte[] def ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } return getBinary( idx, def ); } public byte[] getBinary( int index, byte[] def ) throws KettleValueException { byte[] bin = rowMeta.getBinary( data, index ); if ( bin == null ) { return def; } return bin; } public int compare( RowMetaAndData compare, int[] is, boolean[] bs ) throws KettleValueException { return rowMeta.compare( data, compare.getData(), is ); } public boolean isNumeric( int index ) { return rowMeta.getValueMeta( index ).isNumeric(); } public int size() { return rowMeta.size(); } public ValueMetaInterface getValueMeta( int index ) { return rowMeta.getValueMeta( index ); } public boolean isEmptyValue( String valueName ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } ValueMetaInterface metaType = rowMeta.getValueMeta( idx ); // find by source value type switch ( metaType.getType() ) { case ValueMetaInterface.TYPE_STRING: return rowMeta.getString( data, idx ) == null; case ValueMetaInterface.TYPE_BOOLEAN: return rowMeta.getBoolean( data, idx ) == null; case ValueMetaInterface.TYPE_INTEGER: return rowMeta.getInteger( data, idx ) == null; case ValueMetaInterface.TYPE_NUMBER: return rowMeta.getNumber( data, idx ) == null; } throw new KettleValueException( "Unknown source type" + metaType.getTypeDesc() ); } /** * Converts string value into specified type. Used for constant injection. */ public static Object getStringAsJavaType( String vs, Class<?> destinationType, InjectionTypeConverter converter ) throws KettleValueException { if ( String.class.isAssignableFrom( destinationType ) ) { return converter.string2string( vs ); } else if ( int.class.isAssignableFrom( destinationType ) ) { return converter.string2intPrimitive( vs ); } else if ( Integer.class.isAssignableFrom( destinationType ) ) { return converter.string2integer( vs ); } else if ( long.class.isAssignableFrom( destinationType ) ) { return converter.string2longPrimitive( vs ); } else if ( Long.class.isAssignableFrom( destinationType ) ) { return converter.string2long( vs ); } else if ( boolean.class.isAssignableFrom( destinationType ) ) { return converter.string2booleanPrimitive( vs ); } else if ( Boolean.class.isAssignableFrom( destinationType ) ) { return converter.string2boolean( vs ); } else if ( destinationType.isEnum() ) { return converter.string2enum( destinationType, vs ); } else { throw new RuntimeException( "Wrong value conversion to " + destinationType ); } } /** * Returns value as specified java type using converter. Used for metadata injection. */ public Object getAsJavaType( String valueName, Class<?> destinationType, InjectionTypeConverter converter ) throws KettleValueException { int idx = rowMeta.indexOfValue( valueName ); if ( idx < 0 ) { throw new KettleValueException( "Unknown column '" + valueName + "'" ); } ValueMetaInterface metaType = rowMeta.getValueMeta( idx ); // find by source value type switch ( metaType.getType() ) { case ValueMetaInterface.TYPE_STRING: String vs = rowMeta.getString( data, idx ); return getStringAsJavaType( vs, destinationType, converter ); case ValueMetaInterface.TYPE_BOOLEAN: Boolean vb = rowMeta.getBoolean( data, idx ); if ( String.class.isAssignableFrom( destinationType ) ) { return converter.boolean2string( vb ); } else if ( int.class.isAssignableFrom( destinationType ) ) { return converter.boolean2intPrimitive( vb ); } else if ( Integer.class.isAssignableFrom( destinationType ) ) { return converter.boolean2integer( vb ); } else if ( long.class.isAssignableFrom( destinationType ) ) { return converter.boolean2longPrimitive( vb ); } else if ( Long.class.isAssignableFrom( destinationType ) ) { return converter.boolean2long( vb ); } else if ( boolean.class.isAssignableFrom( destinationType ) ) { return converter.boolean2booleanPrimitive( vb ); } else if ( Boolean.class.isAssignableFrom( destinationType ) ) { return converter.boolean2boolean( vb ); } else if ( destinationType.isEnum() ) { return converter.boolean2enum( destinationType, vb ); } else { throw new RuntimeException( "Wrong value conversion to " + destinationType ); } case ValueMetaInterface.TYPE_INTEGER: Long vi = rowMeta.getInteger( data, idx ); if ( String.class.isAssignableFrom( destinationType ) ) { return converter.integer2string( vi ); } else if ( int.class.isAssignableFrom( destinationType ) ) { return converter.integer2intPrimitive( vi ); } else if ( Integer.class.isAssignableFrom( destinationType ) ) { return converter.integer2integer( vi ); } else if ( long.class.isAssignableFrom( destinationType ) ) { return converter.integer2longPrimitive( vi ); } else if ( Long.class.isAssignableFrom( destinationType ) ) { return converter.integer2long( vi ); } else if ( boolean.class.isAssignableFrom( destinationType ) ) { return converter.integer2booleanPrimitive( vi ); } else if ( Boolean.class.isAssignableFrom( destinationType ) ) { return converter.integer2boolean( vi ); } else if ( destinationType.isEnum() ) { return converter.integer2enum( destinationType, vi ); } else { throw new RuntimeException( "Wrong value conversion to " + destinationType ); } case ValueMetaInterface.TYPE_NUMBER: Double vn = rowMeta.getNumber( data, idx ); if ( String.class.isAssignableFrom( destinationType ) ) { return converter.number2string( vn ); } else if ( int.class.isAssignableFrom( destinationType ) ) { return converter.number2intPrimitive( vn ); } else if ( Integer.class.isAssignableFrom( destinationType ) ) { return converter.number2integer( vn ); } else if ( long.class.isAssignableFrom( destinationType ) ) { return converter.number2longPrimitive( vn ); } else if ( Long.class.isAssignableFrom( destinationType ) ) { return converter.number2long( vn ); } else if ( boolean.class.isAssignableFrom( destinationType ) ) { return converter.number2booleanPrimitive( vn ); } else if ( Boolean.class.isAssignableFrom( destinationType ) ) { return converter.number2boolean( vn ); } else if ( destinationType.isEnum() ) { return converter.number2enum( destinationType, vn ); } else { throw new RuntimeException( "Wrong value conversion to " + destinationType ); } } throw new KettleValueException( "Unknown conversion from " + metaType.getTypeDesc() + " into " + destinationType ); } public void removeValue( String valueName ) throws KettleValueException { int index = rowMeta.indexOfValue( valueName ); if ( index < 0 ) { throw new KettleValueException( "Unable to find '" + valueName + "' in the row" ); } removeValue( index ); } public void removeValue( int index ) { rowMeta.removeValueMeta( index ); data = RowDataUtil.removeItem( data, index ); } }