Skip to content

Commit

Permalink
[PDI-17274] during metadata injection of constant values allocate spa…
Browse files Browse the repository at this point in the history
…ce for collections

- update BeanInjector.setProperty(...) to include allocateCollectionField(...)
  • Loading branch information
NJtwentyone committed Mar 6, 2019
1 parent cbb5427 commit 7e7f27a
Show file tree
Hide file tree
Showing 7 changed files with 643 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
* Copyright (C) 2002-2019 by Hitachi Vantara : http://www.pentaho.com
*
*******************************************************************************
*
Expand Down Expand Up @@ -188,6 +188,10 @@ public String getGroupName() {
return groupName;
}

public List<BeanLevelInfo> getPath() {
return path;
}

public String getDescription() {
return BeanInjectionInfo.this.getDescription( name );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2018 by Hitachi Vantara : http://www.pentaho.com
* Copyright (C) 2002-2019 by Hitachi Vantara : http://www.pentaho.com
*
*******************************************************************************
*
Expand Down Expand Up @@ -32,6 +32,7 @@
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
Expand Down Expand Up @@ -165,7 +166,9 @@ public void setProperty( Object root, String propName, List<RowMetaAndData> data
throw new KettleException( "Property '" + propName + "' not found for injection to " + root.getClass() );
}

String dataName, dataValue;
String dataName;
String dataValue;

if ( data != null ) {
dataName = dataN;
dataValue = null;
Expand All @@ -188,7 +191,10 @@ public void setProperty( Object root, String propName, List<RowMetaAndData> data
setProperty( root, prop, i, data.get( i ), dataName, dataValue );
}
} else {
allocateCollectionField( root, info, propName );
for ( int i = 0;; i++ ) {
// NOTE: case when constant value is provided and need to fill out all entries with the same value
// assumption is the field array/list size allocated to correct size
boolean found = setProperty( root, prop, i, null, null, dataValue );
if ( !found ) {
break;
Expand All @@ -214,7 +220,7 @@ private boolean setProperty( Object root, BeanInjectionInfo.Property prop, int i
Object obj = root;
for ( int i = 1; i < prop.path.size(); i++ ) {
BeanLevelInfo s = prop.path.get( i );
if ( i < prop.path.size() - 1 ) {
if ( i < prop.path.size() - 1 ) { // NOTE: if prop.path.size() > 2, then @InjectionDeep field
// get path
Object next;
switch ( s.dim ) {
Expand Down Expand Up @@ -394,6 +400,198 @@ private List<Object> checkList( BeanLevelInfo s, Object obj, int index ) throws
return index < existList.size() ? existList : null;
}

/**
* Allocate the number of spaces for the {@code fieldName}, in preparation to be filled with call to
* {@link #setProperty(Object, String, List, String )} for constant values.
* @param object class that implements org.pentaho.di.trans.step.StepMetaInterface
* @param beanInjectionInfo
* @param fieldName
*/
void allocateCollectionField( Object object, BeanInjectionInfo beanInjectionInfo, String fieldName ) {

BeanInjectionInfo.Property property = getProperty( beanInjectionInfo, fieldName );
String groupName = ( property != null ) ? property.getGroupName() : null;
if ( groupName == null ) {
return;
}

List<BeanInjectionInfo.Property> groupProperties;
groupProperties = getGroupProperties( beanInjectionInfo, groupName );
Integer maxGroupSize = getMaxSize( groupProperties, object );

// not able to get numeric size
if ( maxGroupSize == null ) {
return;
}

// guaranteed to get at least one field for constant
allocateCollectionField( property, object, Math.max( 1, maxGroupSize ) );
}

/**
* Allocate the number of spaces for the {@code property} with number of space defined by {@code size}.
* @param property
* @param obj
* @param size
*/
void allocateCollectionField( BeanInjectionInfo.Property property, Object obj, int size ) {
BeanLevelInfo beanLevelInfo = getFinalPath( property );
allocateCollectionField( beanLevelInfo, obj, size );
}

/**
* Allocate the number of spaces for the {@code property} with number of space defined by {@code size}.
* @param beanLevelInfo
* @param obj
* @param size
*/
void allocateCollectionField( BeanLevelInfo beanLevelInfo, Object obj, int size ) {
try {
if ( isArray( beanLevelInfo ) ) {
// similar logic as #extendArray
Object newArray = Array.newInstance( beanLevelInfo.leafClass, size );
beanLevelInfo.field.set( obj, newArray );
} else { // LIST
// similar logic as #extendList
List<Object> existList = new ArrayList<>();
beanLevelInfo.field.set( obj, existList );
while ( existList.size() < size ) {
existList.add( null );
}
}
} catch ( Exception e ) {
// do nothing
}
}

/**
* Determines if property is collection ie type list or array.
* @param property
* @return true if collection, false otherwise.
*/
boolean isCollection( BeanInjectionInfo.Property property ) {
if ( property == null ) { // not sure if this is necessary
return false;
}
BeanLevelInfo beanLevelInfo = getFinalPath( property );
return ( beanLevelInfo != null ) ? isCollection( beanLevelInfo ) : null;
}

/**
* Determines if property is collection ie type list or array.
* @param beanLevelInfo
* @return true if collection, false otherwise.
*/
boolean isCollection( BeanLevelInfo beanLevelInfo ) {
return isList( beanLevelInfo ) || isArray( beanLevelInfo );
}

/**
* Determines if property is array.
* @param beanLevelInfo
* @return true if collection, false otherwise.
*/
boolean isArray( BeanLevelInfo beanLevelInfo ) {
return beanLevelInfo.dim == BeanLevelInfo.DIMENSION.ARRAY;
}

/**
* Determines if property is list.
* @param beanLevelInfo
* @return true if collection, false otherwise.
*/
boolean isList( BeanLevelInfo beanLevelInfo ) {
return beanLevelInfo.dim == BeanLevelInfo.DIMENSION.LIST;
}

/**
* Get last path in property list.
* @param property
* @return
*/
BeanLevelInfo getFinalPath( BeanInjectionInfo.Property property ) {
return ( !property.getPath().isEmpty() ) ? property.getPath().get( property.getPath().size() - 1 ) : null;
}

/**
* Get property by name.
* @param beanInjectionInfo
* @param fieldName
* @return
*/
BeanInjectionInfo.Property getProperty( BeanInjectionInfo beanInjectionInfo, String fieldName ) {
return beanInjectionInfo.getProperties().get( fieldName );
}

/**
* Get all properties that belong to the same {@code groupName}
* @param beanInjectionInfo
* @param groupName
* @return
*/
List<BeanInjectionInfo.Property> getGroupProperties( BeanInjectionInfo beanInjectionInfo, String groupName ) {
BeanInjectionInfo.Group group = beanInjectionInfo.getGroups().stream()
.filter( g -> g.getName().equals( groupName ) ).findFirst().orElse( null );

return ( group != null ) ? group.getGroupProperties() : new ArrayList<>();
}

/**
* Determine maximum size property in the collection of {@code properties}
* @param properties
* @param obj
* @return
*/
Integer getMaxSize( Collection<BeanInjectionInfo.Property> properties, Object obj ) {
int max = Integer.MIN_VALUE;

for ( BeanInjectionInfo.Property property: properties ) {
max = Math.max( max,
( isCollection( property )
? getCollectionSize( property, obj )
// if not collection then field of length one
: 1 ) );
}

return ( max != Integer.MIN_VALUE ) ? max : null;
}

/**
* Determine size of {@code property}.
* @param property
* @param obj
* @return
*/
int getCollectionSize( BeanInjectionInfo.Property property, Object obj ) {
BeanLevelInfo beanLevelInfo = getFinalPath( property );
return getCollectionSize( beanLevelInfo, obj );
}

/**
* Determine size of {@code property}.
* @param beanLevelInfo
* @param obj
* @return
*/
int getCollectionSize( BeanLevelInfo beanLevelInfo, Object obj ) {
int size = -1;
try {
if ( isArray( beanLevelInfo ) ) {
// similar logic as BeanInjector#checkArray
Object existArray = beanLevelInfo.field.get( obj );
size = Array.getLength( existArray );
} else { // LIST
// similar logic as BeanInjector#checkList
List<Object> existList = (List<Object>) beanLevelInfo.field.get( obj );
size = existList.size();
}
} catch ( Exception e ) {
// do nothing
}

return size;
}

public void runPostInjectionProcessing( Object object ) {
Method[] methods = object.getClass().getDeclaredMethods();
for ( Method m : methods ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
* Copyright (C) 2002-2019 by Hitachi Vantara : http://www.pentaho.com
*
*******************************************************************************
*
Expand Down Expand Up @@ -42,8 +42,8 @@
/**
* Storage for one step on the bean deep level.
*/
class BeanLevelInfo {
enum DIMENSION {
public class BeanLevelInfo {
public enum DIMENSION {
NONE, ARRAY, LIST
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
* Copyright (C) 2002-2019 by Hitachi Vantara : http://www.pentaho.com
*
*******************************************************************************
*
Expand Down Expand Up @@ -41,4 +41,8 @@ public class MetaBeanLevel1 {
public MetaBeanLevel2 getSub() {
return sub;
}

public void setSub( MetaBeanLevel2 sub ) {
this.sub = sub;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
* Copyright (C) 2002-2019 by Hitachi Vantara : http://www.pentaho.com
*
*******************************************************************************
*
Expand All @@ -22,6 +22,8 @@

package org.pentaho.di.core.injection;

import java.util.List;

public class MetaBeanLevel2 extends MetaBeanLevel2Base {

@Injection( name = "SEPARATOR" )
Expand All @@ -35,13 +37,36 @@ public class MetaBeanLevel2 extends MetaBeanLevel2Base {
@InjectionDeep( prefix = "THIRD" )
private MetaBeanLevel4 filesThird;

@Injection( name = "FILENAME_ARRAY" )
@Injection( name = "FILENAME_ARRAY", group = "FILENAME_LINES2" )
String[] filenames;

@Injection( name = "ASCENDING_LIST", group = "FILENAME_LINES2" )
List<Boolean> ascending;

public List<Boolean> getAscending() {
return ascending;
}

public void setAscending( List<Boolean> ascending ) {
this.ascending = ascending;
}

public void setFilenames( String[] filenames ) {
this.filenames = filenames;
}

public void setFilesThird( MetaBeanLevel4 filesThird ) {
this.filesThird = filesThird;
}

public String[] getFilenames() {
return filenames;
}

public void setSeparator( String separator ) {
this.separator = separator;
}

public String getSeparator() {
return separator;
}
Expand Down
Loading

0 comments on commit 7e7f27a

Please sign in to comment.