/*! ******************************************************************************
*
* 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.xsdvalidator;
import java.util.List;
import java.util.Map;
import org.apache.commons.vfs2.FileObject;
import org.pentaho.di.core.annotations.Step;
import org.pentaho.di.core.CheckResult;
import org.pentaho.di.core.CheckResultInterface;
import org.pentaho.di.core.util.Utils;
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.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.vfs.KettleVFS;
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.resource.ResourceDefinition;
import org.pentaho.di.resource.ResourceNamingInterface;
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;
/*
* Created on 14-08-2007
*
*/
@Step( id = "XSDValidator", image = "XOU.svg", i18nPackageName = "org.pentaho.di.trans.steps.xsdvalidator",
name = "XSDValidator.name", description = "XSDValidator.description",
categoryDescription = "XSDValidator.category",
documentationUrl = "http://wiki.pentaho.com/display/EAI/XSD+Validator" )
public class XsdValidatorMeta extends BaseStepMeta implements StepMetaInterface {
private static Class<?> PKG = XsdValidatorMeta.class; // for i18n purposes, needed by Translator2!!
private String xsdFilename;
private String xmlStream;
private String resultFieldname;
private boolean addValidationMessage;
private String validationMessageField;
private boolean outputStringField;
private String ifXmlValid;
private String ifXmlInvalid;
private boolean xmlSourceFile;
private String xsdDefinedField;
private String xsdSource;
public String SPECIFY_FILENAME = "filename";
public String SPECIFY_FIELDNAME = "fieldname";
public String NO_NEED = "noneed";
public void setXSDSource( String xsdsourcein ) {
this.xsdSource = xsdsourcein;
}
public String getXSDSource() {
return xsdSource;
}
public void setXSDDefinedField( String xsddefinedfieldin ) {
this.xsdDefinedField = xsddefinedfieldin;
}
public String getXSDDefinedField() {
return xsdDefinedField;
}
public boolean getXMLSourceFile() {
return xmlSourceFile;
}
public void setXMLSourceFile( boolean xmlsourcefilein ) {
this.xmlSourceFile = xmlsourcefilein;
}
public String getIfXmlValid() {
return ifXmlValid;
}
public String getIfXmlInvalid() {
return ifXmlInvalid;
}
public void setIfXMLValid( String ifXmlValid ) {
this.ifXmlValid = ifXmlValid;
}
public void setIfXmlInvalid( String ifXmlInvalid ) {
this.ifXmlInvalid = ifXmlInvalid;
}
public boolean getOutputStringField() {
return outputStringField;
}
public void setOutputStringField( boolean outputStringField ) {
this.outputStringField = outputStringField;
}
public String getValidationMessageField() {
return validationMessageField;
}
public void setValidationMessageField( String validationMessageField ) {
this.validationMessageField = validationMessageField;
}
public boolean useAddValidationMessage() {
return addValidationMessage;
}
public void setAddValidationMessage( boolean addValidationMessage ) {
this.addValidationMessage = addValidationMessage;
}
public XsdValidatorMeta() {
super(); // allocate BaseStepMeta
}
/**
* @return Returns the XSD filename.
*/
public String getXSDFilename() {
return xsdFilename;
}
public String getResultfieldname() {
return resultFieldname;
}
public String getXMLStream() {
return xmlStream;
}
/**
* @param xdsFilename
* The XSD filename to set.
*/
public void setXSDfilename( String xdsFilename ) {
this.xsdFilename = xdsFilename;
}
public void setResultfieldname( String resultFieldname ) {
this.resultFieldname = resultFieldname;
}
public void setXMLStream( String xmlStream ) {
this.xmlStream = xmlStream;
}
public void loadXML( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException {
readData( stepnode );
}
public Object clone() {
XsdValidatorMeta retval = (XsdValidatorMeta) super.clone();
return retval;
}
private void readData( Node stepnode ) throws KettleXMLException {
try {
xsdFilename = XMLHandler.getTagValue( stepnode, "xdsfilename" );
xmlStream = XMLHandler.getTagValue( stepnode, "xmlstream" );
resultFieldname = XMLHandler.getTagValue( stepnode, "resultfieldname" );
xsdDefinedField = XMLHandler.getTagValue( stepnode, "xsddefinedfield" );
xsdSource = XMLHandler.getTagValue( stepnode, "xsdsource" );
addValidationMessage = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "addvalidationmsg" ) );
validationMessageField = XMLHandler.getTagValue( stepnode, "validationmsgfield" );
ifXmlValid = XMLHandler.getTagValue( stepnode, "ifxmlvalid" );
ifXmlInvalid = XMLHandler.getTagValue( stepnode, "ifxmlunvalid" );
outputStringField = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "outputstringfield" ) );
xmlSourceFile = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "xmlsourcefile" ) );
} catch ( Exception e ) {
throw new KettleXMLException( BaseMessages.getString( PKG,
"XsdValidatorMeta.Exception.UnableToLoadStepInfoFromXML" ), e );
}
}
public void setDefault() {
xsdFilename = "";
xmlStream = "";
resultFieldname = "result";
addValidationMessage = false;
validationMessageField = "ValidationMsgField";
ifXmlValid = "";
ifXmlInvalid = "";
outputStringField = false;
xmlSourceFile = false;
xsdDefinedField = "";
xsdSource = SPECIFY_FILENAME;
}
public void getFields( RowMetaInterface inputRowMeta, String name, RowMetaInterface[] info, StepMeta nextStep,
VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {
if ( !Utils.isEmpty( resultFieldname ) ) {
if ( outputStringField ) {
// Output field (String)
ValueMetaInterface v =
new ValueMeta( space.environmentSubstitute( getResultfieldname() ), ValueMeta.TYPE_STRING );
inputRowMeta.addValueMeta( v );
} else {
// Output field (boolean)
ValueMetaInterface v =
new ValueMeta( space.environmentSubstitute( getResultfieldname() ), ValueMeta.TYPE_BOOLEAN );
inputRowMeta.addValueMeta( v );
}
}
// Add String Field that contain validation message (most the time, errors)
if ( addValidationMessage && !Utils.isEmpty( validationMessageField ) ) {
ValueMetaInterface v =
new ValueMeta( space.environmentSubstitute( validationMessageField ), ValueMeta.TYPE_STRING );
inputRowMeta.addValueMeta( v );
}
}
public String getXML() {
StringBuffer retval = new StringBuffer();
retval.append( " " + XMLHandler.addTagValue( "xdsfilename", xsdFilename ) );
retval.append( " " + XMLHandler.addTagValue( "xmlstream", xmlStream ) );
retval.append( " " + XMLHandler.addTagValue( "resultfieldname", resultFieldname ) );
retval.append( " " + XMLHandler.addTagValue( "addvalidationmsg", addValidationMessage ) );
retval.append( " " + XMLHandler.addTagValue( "validationmsgfield", validationMessageField ) );
retval.append( " " + XMLHandler.addTagValue( "ifxmlunvalid", ifXmlInvalid ) );
retval.append( " " + XMLHandler.addTagValue( "ifxmlvalid", ifXmlValid ) );
retval.append( " " + XMLHandler.addTagValue( "outputstringfield", outputStringField ) );
retval.append( " " + XMLHandler.addTagValue( "xmlsourcefile", xmlSourceFile ) );
retval.append( " " + XMLHandler.addTagValue( "xsddefinedfield", xsdDefinedField ) );
retval.append( " " + XMLHandler.addTagValue( "xsdsource", xsdSource ) );
return retval.toString();
}
public void readRep( Repository rep, IMetaStore metaStore, ObjectId id_step, List<DatabaseMeta> databases )
throws KettleException {
try {
xsdFilename = rep.getStepAttributeString( id_step, "xdsfilename" );
xmlStream = rep.getStepAttributeString( id_step, "xmlstream" );
resultFieldname = rep.getStepAttributeString( id_step, "resultfieldname" );
xmlSourceFile = rep.getStepAttributeBoolean( id_step, "xmlsourcefile" );
addValidationMessage = rep.getStepAttributeBoolean( id_step, "addvalidationmsg" );
validationMessageField = rep.getStepAttributeString( id_step, "validationmsgfield" );
ifXmlValid = rep.getStepAttributeString( id_step, "ifxmlvalid" );
ifXmlInvalid = rep.getStepAttributeString( id_step, "ifxmlunvalid" );
outputStringField = rep.getStepAttributeBoolean( id_step, "outputstringfield" );
xsdDefinedField = rep.getStepAttributeString( id_step, "xsddefinedfield" );
xsdSource = rep.getStepAttributeString( id_step, "xsdsource" );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString( PKG,
"XsdValidatorMeta.Exception.UnexpectedErrorInReadingStepInfo" ), e );
}
}
public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step )
throws KettleException {
try {
rep.saveStepAttribute( id_transformation, id_step, "xdsfilename", xsdFilename );
rep.saveStepAttribute( id_transformation, id_step, "xmlstream", xmlStream );
rep.saveStepAttribute( id_transformation, id_step, "resultfieldname", resultFieldname );
rep.saveStepAttribute( id_transformation, id_step, "xmlsourcefile", xmlSourceFile );
rep.saveStepAttribute( id_transformation, id_step, "addvalidationmsg", addValidationMessage );
rep.saveStepAttribute( id_transformation, id_step, "validationmsgfield", validationMessageField );
rep.saveStepAttribute( id_transformation, id_step, "ifxmlvalid", ifXmlValid );
rep.saveStepAttribute( id_transformation, id_step, "ifxmlunvalid", ifXmlInvalid );
rep.saveStepAttribute( id_transformation, id_step, "outputstringfield", outputStringField );
rep.saveStepAttribute( id_transformation, id_step, "xsddefinedfield", xsdDefinedField );
rep.saveStepAttribute( id_transformation, id_step, "xsdsource", xsdSource );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString( PKG, "XsdValidatorMeta.Exception.UnableToSaveStepInfo" )
+ id_step, e );
}
}
public void check( List<CheckResultInterface> remarks, TransMeta transMeta, StepMeta stepinfo, RowMetaInterface prev,
String[] input, String[] output, RowMetaInterface info, VariableSpace space, Repository repository,
IMetaStore metaStore ) {
CheckResult cr;
// Check XML stream field
if ( Utils.isEmpty( xmlStream ) ) {
cr =
new CheckResult( CheckResult.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.XMLStreamFieldEmpty" ), stepinfo );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResult.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.XMLStreamFieldOK" ), stepinfo );
remarks.add( cr );
}
// Check result fieldname
if ( Utils.isEmpty( resultFieldname ) ) {
cr =
new CheckResult( CheckResult.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.ResultFieldEmpty" ), stepinfo );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResult.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.ResultFieldOK" ), stepinfo );
remarks.add( cr );
}
if ( xsdSource.equals( SPECIFY_FILENAME ) ) {
if ( Utils.isEmpty( xsdFilename ) ) {
cr =
new CheckResult( CheckResult.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.XSDFieldEmpty" ), stepinfo );
remarks.add( cr );
}
}
if ( prev != null && prev.size() > 0 ) {
cr =
new CheckResult( CheckResult.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.ConnectedStepOK", String.valueOf( prev.size() ) ), stepinfo );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResult.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.NoInputReceived" ), stepinfo );
remarks.add( cr );
}
// See if we have input streams leading to this step!
if ( input.length > 0 ) {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.ExpectedInputOk" ), stepinfo );
remarks.add( cr );
} else {
cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, BaseMessages.getString( PKG,
"XsdValidatorMeta.CheckResult.ExpectedInputError" ), stepinfo );
remarks.add( cr );
}
}
public StepInterface getStep( StepMeta stepMeta, StepDataInterface stepDataInterface, int cnr, TransMeta transMeta,
Trans trans ) {
return new XsdValidator( stepMeta, stepDataInterface, cnr, transMeta, trans );
}
public StepDataInterface getStepData() {
return new XsdValidatorData();
}
public boolean supportsErrorHandling() {
return true;
}
/**
* Since the exported transformation that runs this will reside in a ZIP file, we can't reference files relatively. So
* what this does is turn the name of files into absolute paths OR it simply includes the resource in the ZIP file.
* For now, we'll simply turn it into an absolute path and pray that the file is on a shared drive or something like
* that.
*
* @param space
* the variable space to use
* @param definitions
* @param resourceNamingInterface
* @param repository
* The repository to optionally load other resources from (to be converted to XML)
* @param metaStore
* the metaStore in which non-kettle metadata could reside.
*
* @return the filename of the exported resource
*/
public String exportResources( VariableSpace space, Map<String, ResourceDefinition> definitions,
ResourceNamingInterface resourceNamingInterface, Repository repository, IMetaStore metaStore )
throws KettleException {
try {
// The object that we're modifying here is a copy of the original!
// So let's change the filename from relative to absolute by grabbing the file object...
// In case the name of the file comes from previous steps, forget about this!
//
// From : ${Internal.Transformation.Filename.Directory}/../foo/bar.xsd
// To : /home/matt/test/files/foo/bar.xsd
//
if ( !Utils.isEmpty( xsdFilename ) ) {
FileObject fileObject = KettleVFS.getFileObject( space.environmentSubstitute( xsdFilename ), space );
xsdFilename = resourceNamingInterface.nameResource( fileObject, space, true );
return xsdFilename;
}
return null;
} catch ( Exception e ) {
throw new KettleException( e );
}
}
}