/*! ******************************************************************************
*
* 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.trans.steps.xmljoin;
import java.util.Arrays;
import java.util.List;
import org.pentaho.di.core.annotations.Step;
import org.pentaho.di.core.CheckResult;
import org.pentaho.di.core.CheckResultInterface;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.exception.KettleXMLException;
import org.pentaho.di.core.injection.Injection;
import org.pentaho.di.core.injection.InjectionSupported;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMeta;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.metastore.api.IMetaStore;
import org.w3c.dom.Node;
/**
* This class knows how to handle the MetaData for the XML join step
*
* @since 30-04-2008
*
*/
@Step( id = "XMLJoin", image = "XJN.svg", i18nPackageName = "org.pentaho.di.trans.steps.xmljoin",
name = "XMLJoin.name", description = "XMLJoin.description", categoryDescription = "XMLJoin.category",
documentationUrl = "http://wiki.pentaho.com/display/EAI/XML+Join" )
@InjectionSupported( localizationPrefix = "XMLJoin.Injection." )
public class XMLJoinMeta extends BaseStepMeta implements StepMetaInterface {
private static Class<?> PKG = XMLJoinMeta.class; // for i18n purposes, needed by Translator2!!
/** The base name of the output file */
/** Flag: execute complex join */
@Injection( name = "COMPLEX_JOIN" )
private boolean complexJoin;
/** What step holds the xml string to join into */
@Injection( name = "TARGET_XML_STEP" )
private String targetXMLstep;
/** What field holds the xml string to join into */
@Injection( name = "TARGET_XML_FIELD" )
private String targetXMLfield;
/** What field holds the XML tags to join */
@Injection( name = "SOURCE_XML_FIELD" )
private String sourceXMLfield;
/** The name value containing the resulting XML fragment */
@Injection( name = "VALUE_XML_FIELD" )
private String valueXMLfield;
/** The name of the repeating row XML element */
@Injection( name = "TARGET_XPATH" )
private String targetXPath;
/** What step holds the xml strings to join */
@Injection( name = "SOURCE_XML_STEP" )
private String sourceXMLstep;
/** What field holds the join compare value */
@Injection( name = "JOIN_COMPARE_FIELD" )
private String joinCompareField;
/** The encoding to use for reading: null or empty string means system default encoding */
@Injection( name = "ENCODING" )
private String encoding;
/** Flag: execute complex join */
@Injection( name = "OMIT_XML_HEADER" )
private boolean omitXMLHeader;
/** Flag: omit null values from result xml */
@Injection( name = "OMIT_NULL_VALUES" )
private boolean omitNullValues;
public XMLJoinMeta() {
super(); // allocate BaseStepMeta
}
public void loadXML( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException {
readData( stepnode );
}
public Object clone() {
XMLJoinMeta retval = (XMLJoinMeta) super.clone();
return retval;
}
private void readData( Node stepnode ) throws KettleXMLException {
try {
valueXMLfield = XMLHandler.getTagValue( stepnode, "valueXMLfield" );
targetXMLstep = XMLHandler.getTagValue( stepnode, "targetXMLstep" );
targetXMLfield = XMLHandler.getTagValue( stepnode, "targetXMLfield" );
sourceXMLstep = XMLHandler.getTagValue( stepnode, "sourceXMLstep" );
sourceXMLfield = XMLHandler.getTagValue( stepnode, "sourceXMLfield" );
targetXPath = XMLHandler.getTagValue( stepnode, "targetXPath" );
joinCompareField = XMLHandler.getTagValue( stepnode, "joinCompareField" );
encoding = XMLHandler.getTagValue( stepnode, "encoding" );
complexJoin = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "complexJoin" ) );
omitXMLHeader = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "omitXMLHeader" ) );
omitNullValues = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "omitNullValues" ) );
} catch ( Exception e ) {
throw new KettleXMLException( "Unable to load step info from XML", e );
}
}
public void setDefault() {
// complexJoin = false;
encoding = Const.XML_ENCODING;
}
public void getFields( RowMetaInterface row, String name, RowMetaInterface[] info, StepMeta nextStep,
VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {
ValueMetaInterface v = new ValueMeta( this.getValueXMLfield(), ValueMetaInterface.TYPE_STRING );
v.setOrigin( name );
RowMetaInterface rowMeta = ( (TransMeta) space ) .getStepFields( getTargetXMLstep() ).clone();
if ( rowMeta != null ) {
rowMeta.addValueMeta( v );
row.setValueMetaList( rowMeta.getValueMetaList() );
} else {
row.setValueMetaList( Arrays.asList( v ) );
}
}
public String getXML() {
StringBuffer retval = new StringBuffer( 500 );
retval.append( " " ).append( XMLHandler.addTagValue( "valueXMLField", valueXMLfield ) );
retval.append( " " ).append( XMLHandler.addTagValue( "targetXMLstep", targetXMLstep ) );
retval.append( " " ).append( XMLHandler.addTagValue( "targetXMLfield", targetXMLfield ) );
retval.append( " " ).append( XMLHandler.addTagValue( "sourceXMLstep", sourceXMLstep ) );
retval.append( " " ).append( XMLHandler.addTagValue( "sourceXMLfield", sourceXMLfield ) );
retval.append( " " ).append( XMLHandler.addTagValue( "complexJoin", complexJoin ) );
retval.append( " " ).append( XMLHandler.addTagValue( "joinCompareField", joinCompareField ) );
retval.append( " " ).append( XMLHandler.addTagValue( "targetXPath", targetXPath ) );
retval.append( " " ).append( XMLHandler.addTagValue( "encoding", encoding ) );
retval.append( " " ).append( XMLHandler.addTagValue( "omitXMLHeader", omitXMLHeader ) );
retval.append( " " ).append( XMLHandler.addTagValue( "omitNullValues", omitNullValues ) );
return retval.toString();
}
public void readRep( Repository rep, IMetaStore metaStore, ObjectId id_step, List<DatabaseMeta> databases )
throws KettleException {
try {
targetXMLstep = rep.getStepAttributeString( id_step, "targetXMLstep" );
targetXMLfield = rep.getStepAttributeString( id_step, "targetXMLfield" );
sourceXMLstep = rep.getStepAttributeString( id_step, "sourceXMLstep" );
sourceXMLfield = rep.getStepAttributeString( id_step, "sourceXMLfield" );
targetXPath = rep.getStepAttributeString( id_step, "targetXPath" );
complexJoin = rep.getStepAttributeBoolean( id_step, "complexJoin" );
joinCompareField = rep.getStepAttributeString( id_step, "joinCompareField" );
valueXMLfield = rep.getStepAttributeString( id_step, "valueXMLfield" );
encoding = rep.getStepAttributeString( id_step, "encoding" );
omitXMLHeader = rep.getStepAttributeBoolean( id_step, "omitXMLHeader" );
omitNullValues = rep.getStepAttributeBoolean( id_step, "omitNullValues" );
} catch ( Exception e ) {
throw new KettleException( "Unexpected error reading step information from the repository", e );
}
}
public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step )
throws KettleException {
try {
rep.saveStepAttribute( id_transformation, id_step, "valueXMLfield", valueXMLfield );
rep.saveStepAttribute( id_transformation, id_step, "targetXMLstep", targetXMLstep );
rep.saveStepAttribute( id_transformation, id_step, "targetXMLfield", targetXMLfield );
rep.saveStepAttribute( id_transformation, id_step, "sourceXMLstep", sourceXMLstep );
rep.saveStepAttribute( id_transformation, id_step, "sourceXMLfield", sourceXMLfield );
rep.saveStepAttribute( id_transformation, id_step, "complexJoin", complexJoin );
rep.saveStepAttribute( id_transformation, id_step, "targetXPath", targetXPath );
rep.saveStepAttribute( id_transformation, id_step, "joinCompareField", joinCompareField );
rep.saveStepAttribute( id_transformation, id_step, "encoding", encoding );
rep.saveStepAttribute( id_transformation, id_step, "omitXMLHeader", omitXMLHeader );
rep.saveStepAttribute( id_transformation, id_step, "omitNullValues", omitNullValues );
} catch ( Exception e ) {
throw new KettleException( "Unable to save step information to the repository for id_step=" + id_step, e );
}
}
public void check( List<CheckResultInterface> remarks, TransMeta transMeta, StepMeta stepMeta, RowMetaInterface prev,
String[] input, String[] output, RowMetaInterface info, VariableSpace space, Repository repository,
IMetaStore metaStore ) {
CheckResult cr;
// checks for empty field which are required
if ( this.targetXMLstep == null || this.targetXMLstep.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLStepNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLStepSpecified" ), stepMeta );
remarks.add( cr );
}
if ( this.targetXMLfield == null || this.targetXMLfield.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLFieldNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLFieldSpecified" ), stepMeta );
remarks.add( cr );
}
if ( this.sourceXMLstep == null || this.sourceXMLstep.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLStepNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLStepSpecified" ), stepMeta );
remarks.add( cr );
}
if ( this.sourceXMLfield == null || this.sourceXMLfield.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLFieldNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLFieldSpecified" ), stepMeta );
remarks.add( cr );
}
if ( this.valueXMLfield == null || this.valueXMLfield.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.ResultFieldNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.ResultFieldSpecified" ), stepMeta );
remarks.add( cr );
}
if ( this.targetXPath == null || this.targetXPath.length() == 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXPathNotSpecified" ), stepMeta );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXPathSpecified" ), stepMeta );
remarks.add( cr );
}
// See if we have the right input streams leading to this step!
if ( input.length > 0 ) {
boolean targetStepFound = false;
boolean sourceStepFound = false;
for ( int i = 0; i < input.length; i++ ) {
if ( this.targetXMLstep != null && this.targetXMLstep.equals( input[i] ) ) {
targetStepFound = true;
cr =
new CheckResult( CheckResult.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLStepFound", this.targetXMLstep ), stepMeta );
remarks.add( cr );
}
if ( this.sourceXMLstep != null && this.sourceXMLstep.equals( input[i] ) ) {
sourceStepFound = true;
cr =
new CheckResult( CheckResult.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLStepFound", this.sourceXMLstep ), stepMeta );
remarks.add( cr );
}
}
if ( !targetStepFound ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.TargetXMLStepNotFound", this.targetXMLstep ), stepMeta );
remarks.add( cr );
}
if ( !sourceStepFound ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.SourceXMLStepNotFound", this.sourceXMLstep ), stepMeta );
remarks.add( cr );
}
} else {
cr =
new CheckResult( CheckResult.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XMLJoin.CheckResult.ExpectedInputError" ), stepMeta );
remarks.add( cr );
}
}
public StepInterface getStep( StepMeta stepMeta, StepDataInterface stepDataInterface, int cnr, TransMeta transMeta,
Trans trans ) {
return new XMLJoin( stepMeta, stepDataInterface, cnr, transMeta, trans );
}
public StepDataInterface getStepData() {
return new XMLJoinData();
}
public boolean isComplexJoin() {
return complexJoin;
}
public void setComplexJoin( boolean complexJoin ) {
this.complexJoin = complexJoin;
}
public String getTargetXMLstep() {
return targetXMLstep;
}
public void setTargetXMLstep( String targetXMLstep ) {
this.targetXMLstep = targetXMLstep;
}
public String getTargetXMLfield() {
return targetXMLfield;
}
public void setTargetXMLfield( String targetXMLfield ) {
this.targetXMLfield = targetXMLfield;
}
public String getSourceXMLstep() {
return sourceXMLstep;
}
public void setSourceXMLstep( String targetXMLstep ) {
this.sourceXMLstep = targetXMLstep;
}
public String getSourceXMLfield() {
return sourceXMLfield;
}
public void setSourceXMLfield( String sourceXMLfield ) {
this.sourceXMLfield = sourceXMLfield;
}
public String getValueXMLfield() {
return valueXMLfield;
}
public void setValueXMLfield( String valueXMLfield ) {
this.valueXMLfield = valueXMLfield;
}
public String getTargetXPath() {
return targetXPath;
}
public void setTargetXPath( String targetXPath ) {
this.targetXPath = targetXPath;
}
public String getJoinCompareField() {
return joinCompareField;
}
public void setJoinCompareField( String joinCompareField ) {
this.joinCompareField = joinCompareField;
}
public boolean excludeFromRowLayoutVerification() {
return true;
}
public boolean isOmitXMLHeader() {
return omitXMLHeader;
}
public void setOmitXMLHeader( boolean omitXMLHeader ) {
this.omitXMLHeader = omitXMLHeader;
}
public void setOmitNullValues( boolean omitNullValues ) {
this.omitNullValues = omitNullValues;
}
public boolean isOmitNullValues() {
return omitNullValues;
}
public String getEncoding() {
return encoding;
}
public void setEncoding( String encoding ) {
this.encoding = encoding;
}
}