package org.ebayopensource.turmeric.tools.codegen.fastserformat.protobuf.validator;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import org.ebayopensource.turmeric.runtime.codegen.common.FastSerFormatType;
import org.ebayopensource.turmeric.runtime.codegen.common.FastSerFormatValidationError;
import org.ebayopensource.turmeric.runtime.codegen.common.SchemaNode;
import org.ebayopensource.turmeric.runtime.codegen.common.SchemaNodeAttribute;
import org.ebayopensource.turmeric.runtime.codegen.common.ValidationRule;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.tools.codegen.CodeGenContext;
import org.ebayopensource.turmeric.tools.codegen.InputOptions;
import org.ebayopensource.turmeric.tools.codegen.exception.CodeGenFailedException;
import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.WSDLParserConstants;
import org.ebayopensource.turmeric.tools.codegen.util.CodeGenUtil;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.LocatorImpl;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* This class does the validations defined in ValidationRule.
* The metadata file ValidationData.xml is used to perform the validation.
*
* A particular validation rule can be applicable for one or more fast ser formats.
* So this class executes validation rules which are applicable for supported fast ser formats.
*
* Lets say the validation rule A is applicable for protobuf and rule B is applicable for avro.
* If service supportes protobuf, only rule A is executed.
* If service supports avro, only rule B is executed.
*
* @author rkulandaivel
*
*/
public class FastSerFormatValidationHandler implements SchemaConstuctConstants{
private Set<ValidationRule> m_rulesTobeValidated = new HashSet<ValidationRule>();
private List<FastSerFormatValidationError> m_errors = new ArrayList<FastSerFormatValidationError>();
private SchemaNode m_rootNode = new SchemaNode();
private List<FastSerFormatType> m_formatsWhichRequireValidation = null;
private SchemaNodeRepresentationByType m_typesMap = new SchemaNodeRepresentationByType();
private static Logger s_logger = LogManager
.getInstance(FastSerFormatValidationHandler.class);
private static final String MARKET_PLACE_NAMESPACE = "http://www.ebay.com/marketplace/services";
private static Logger getLogger() {
return s_logger;
}
private static final String EMPTY_STRING = "";
private static final String REPLACE_ARG_0 = "{0}";
private static final String REPLACE_ARG_1 = "{1}";
private static final String REPLACE_ARG_2 = "{2}";
private static final String REPLACE_ARG_3 = "{3}";
public static final String EMPTY_WSDL_PATH = "The wsdl path is empty. Could not perform validation.";
private FastSerFormatValidationHandler(List<FastSerFormatType> formatsWhichRequireValidation){
//Consolidate only the list of rules that this service or type library supports
FastSerFormatValidationData data = FastSerFormatValidationData.getInstance();
for(FastSerFormatType format : formatsWhichRequireValidation){
m_rulesTobeValidated.addAll( data.getRulesForFormat( format ) );
}
this.m_formatsWhichRequireValidation = formatsWhichRequireValidation;
}
/**
* Returns the template error object.
* @param rule
* @return
*/
private FastSerFormatValidationError getErrorTemplate( ValidationRule rule ){
return FastSerFormatValidationData.getInstance().getTemplateData( rule );
}
/**
* Creates Validation Error object by mapping from the template object and from the schema node.
* The Description is taken from template object.
* All other info like line no, columnno, file name are taken from the schema node.
*
* @param currentNode
* @param rule
* @return
*/
private FastSerFormatValidationError createError(SchemaNode currentNode, ValidationRule rule){
FastSerFormatValidationError template = FastSerFormatValidationData.getInstance().getTemplateData( rule );
FastSerFormatValidationError error = new FastSerFormatValidationError();
error.setError(rule);
error.setLineNumber( currentNode.getLineNumber() );
error.setColumnNumber( currentNode.getColumnNumber() );
error.setFileName( currentNode.getFileName() );
error.setDescription( template.getDescription() );
return error;
}
/**
* This method returns the string representation of supported types string
* for the specified validation rule.
* The output format is [protobuf, avro]
* @param rule
* @return
*/
private String getSupportedTypesString(ValidationRule rule){
List<FastSerFormatType> formats = FastSerFormatValidationData.getInstance().getApplicableFormats(rule);
StringBuilder buff = new StringBuilder( "[ " );
int i = 0;
for( FastSerFormatType format : formats ){
if( m_formatsWhichRequireValidation.contains(format) ){
if(i > 0){
buff.append( ", " );
}
buff.append( format.value() );
}
}
buff.append( " ]" );
return buff.toString();
}
/**
* This method logs the details of the schema node like
* name, line no, column no, file name.
*
* @param currentNode
* @param methodName
*/
private void log(SchemaNode currentNode, String methodName){
if( !getLogger().isLoggable(Level.INFO) ){
return;
}
String message = "Scanning Schema Node inside " + methodName;
message = message + ". Node Name : " + currentNode.getNodeName();
for( SchemaNodeAttribute attr : currentNode.getAttributes() ){
message = message + "; " + attr.getAttributeName() + " : ";
message = message + attr.getAttributeValue();
}
message = message + "; Line : " + currentNode.getLineNumber();
message = message + "; Column : " + currentNode.getColumnNumber();
message = message + "; FileName : " + currentNode.getFileName();
message = message + ".";
getLogger().info( message );
}
/**
* This method logs the error details of the schema node.
*
* @param error
* @param currentNode
*/
private void log(FastSerFormatValidationError error, SchemaNode currentNode){
if( !getLogger().isLoggable(Level.INFO) ){
return;
}
String message = "The schema node contains validation error.";
message = message + " Node Name : " + currentNode.getNodeName();
message = message + "; Rule : " + error.getError();
message = message + "; Description : " + error.getDescription();
message = message + "; Line : " + error.getLineNumber();
message = message + "; Column : " + error.getColumnNumber();
message = message + "; FileName : " + error.getFileName();
getLogger().info( message );
}
/**
* This method performs the anonymous type validations.
* It captures usage of anonymous types at second level or deeper.
* If the root element node which is directly under schema tag uses anonymous type
* then it is allowed.
* If the element which is not root uses anonymous type then it is captured.
*
* @param currentNode
*/
private void doAnonymousCheck( SchemaNode currentNode ){
boolean rootNode = Util.isRootNodeInSchema( currentNode );
boolean isElementNode = Util.isInValidNodeName( currentNode, ELEMENT );
boolean isAttributeNode = Util.isInValidNodeName( currentNode, ATTRIBUTE );
if( isElementNode || isAttributeNode){
if( !currentNode.isTypeAttrExists() && !currentNode.isRefAttrExists() ){
boolean usesAnonymousType = false;
for( SchemaNode child : currentNode.getChildNodes() ){
if( COMPLEXTYPE.equals(child.getNodeName()) ||
SIMPLETYPE.equals(child.getNodeName()) ){
if( !rootNode ){
FastSerFormatValidationError error = createError(currentNode, ValidationRule.ANONYMOUS_TYPE_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, currentNode );
desc = desc.replace(REPLACE_ARG_1, isElementNode ? ELEMENT : ATTRIBUTE);
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ANONYMOUS_TYPE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
usesAnonymousType = true;
}
}
//The element is not having type attribute and also does not use anonymous type
if( !usesAnonymousType ){
ValidationRule rule = isElementNode ? ValidationRule.ELEMENT_WITHOUT_TYPE_NOT_SUPPORTED : ValidationRule.ATTRIBUTES_WITHOUT_TYPE_NOT_SUPPORTED;
FastSerFormatValidationError error = createError(currentNode, rule );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( rule ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
}
/**
* Only the schemas which follow http://www.w3.org/2001/XMLSchema
* are supported. The schemas which follow older schema definitions are not supported.
*
* This method throws immediate exception, instead of adding to error collections.
* The reason is that all the validations are written with assumption that schema will follow
* http://www.w3.org/2001/XMLSchema.
* So if namespace is incorrect then no point in validation remaining schema.
*
* @param uri
* @throws CodeGenFailedException
*/
public void doNamespaceValidation(String uri, String fileName) throws CodeGenFailedException{
if( m_rulesTobeValidated.contains( ValidationRule.OLD_SCHEMAS_NOT_SUPPORTED ) ){
if( WSDLParserConstants.NS_URI_1999_SCHEMA_XSD.equals( uri )
|| WSDLParserConstants.NS_URI_2000_SCHEMA_XSD.equals( uri ) ){
FastSerFormatValidationError template = getErrorTemplate( ValidationRule.OLD_SCHEMAS_NOT_SUPPORTED );
String desc = template.getDescription();
desc = desc.replace(REPLACE_ARG_0, fileName );
desc = desc.replace(REPLACE_ARG_1, uri );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.OLD_SCHEMAS_NOT_SUPPORTED ) );
throw new CodeGenFailedException( desc );
}
}
}
/**
* The wsdl should not have more than one namespace.
* If wsdl has more than one namespce then add a validation rule.
*
* This method is called during end tag validation of definitions.
* Since xsd does not have definitions
* The code should not fail for xsd validation.
*
*
* @param currentNode
*/
private void checkForMultipleNamespace( SchemaNode currentNode ){
//xpath for schema node in wsdl is
//definitions/types/xs:schema
//get the xpath "definitions/types"
SchemaNode typesNode = null;
List<SchemaNode> typesNodes = m_typesMap.getSchemaNodesList(TYPES);
for( SchemaNode node : typesNodes ){
//the 'definitions' would have lots of child nodes like 'message','portType'
//so instead of traversing through all child nodes of 'definitions'
//traverse through available 'types' node and check the parent
if( node.getParentNode() != null && node.getParentNode() == currentNode ){
typesNode = node;
break;
}
}
if( typesNode == null ){
String message = "Types node is null which is not possible on a valid wsdl. The reason could be due to inconsistent codechange on SchemaNodeRepresentationByType";
getLogger().log(Level.SEVERE, message );
//throw as runtime as this could be possible only because of inconsistent code change related to 'SchemaNodeRepresentationByType'
throw new RuntimeException( message );
}
//i.e. xpath = definitions/types
if( typesNode.getChildNodes().size() > 1 ){
//multiple namespace
FastSerFormatValidationError error = createError(currentNode, ValidationRule.MULTIPLE_NAMESPACE_WSDL_IS_NOT_SUPPORTED );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ANY_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
/**
* This is the call back method of SAX parser event "endElement"
* This method does validations which are applicable on endElement like checking anonymous types.
*
* @param currentNode
*/
public void doEndElementValidation(SchemaNode currentNode){
log(currentNode, "doStartElementValidation");
if( m_rulesTobeValidated.contains( ValidationRule.ANONYMOUS_TYPE_NOT_SUPPORTED ) ){
doAnonymousCheck(currentNode );
}
if( m_rulesTobeValidated.contains( ValidationRule.ANY_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, DEFINITIONS ) ){
checkForMultipleNamespace( currentNode );
return ;
}
}
}
/**
* this method escapes validation of ANY_NOT_SUPPORTED if
* the type is part of namespace http://www.ebay.com/marketplace/services.
*
* This method does not do validation for node name.
* It will just check for namespace.
*
* @param currentNode
* @return
*/
private boolean escapeValidationForAny( SchemaNode currentNode ){
SchemaNode surroundingType = Util.getSurroundingType(currentNode);
if( surroundingType == null ){
return false;
}
if( MARKET_PLACE_NAMESPACE.equals(surroundingType.getTargetNamespace() ) ){
return true;
}
if( surroundingType.getLibraryInfo() == null ){
return false;
}
if( MARKET_PLACE_NAMESPACE.equals( surroundingType.getLibraryInfo().getNamespace() ) ){
return true;
}
return false;
}
/**
* This is the call back method of SAX parser event startElement.
* This method does all validations applicable on start element.
*
* @param currentNode
*/
public void doStartElementValidation(SchemaNode currentNode){
FastSerFormatValidationError error = null;
log(currentNode, "doStartElementValidation");
if( m_rulesTobeValidated.contains( ValidationRule.ANY_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, ANY ) && !escapeValidationForAny( currentNode )){
error = createError(currentNode, ValidationRule.ANY_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ANY_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.ANY_ATTRIBUTE_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, ANY_ATTRIBUTE ) ){
error = createError(currentNode, ValidationRule.ANY_ATTRIBUTE_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ANY_ATTRIBUTE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.FIELD_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, FIELD ) ){
error = createError(currentNode, ValidationRule.FIELD_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingElement( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.FIELD_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.KEY_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, KEY ) ){
error = createError(currentNode, ValidationRule.KEY_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingElement( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.KEY_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.KEY_REF_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, KEY_REF ) ){
error = createError(currentNode, ValidationRule.KEY_REF_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingElement( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.KEY_REF_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.NOTATION_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, NOTATION ) ){
error = createError(currentNode, ValidationRule.NOTATION_NOT_SUPPORTED );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.NOTATION_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.REDEFINE_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, REDEFINE ) ){
error = createError(currentNode, ValidationRule.REDEFINE_NOT_SUPPORTED );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.REDEFINE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.SELECTOR_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, SELECTOR ) ){
error = createError(currentNode, ValidationRule.SELECTOR_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingElement( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.SELECTOR_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.UNION_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, UNION ) ){
error = createError(currentNode, ValidationRule.UNION_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.UNION_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.UNIQUE_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, UNIQUE ) ){
error = createError(currentNode, ValidationRule.UNIQUE_NOT_SUPPORTED );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingElement( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.UNIQUE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
if( m_rulesTobeValidated.contains( ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_CHOICE ) ){
if( Util.isInValidNodeName( currentNode, CHOICE ) ){
if( currentNode.isMaxoccursAttrExists() || Util.getAttributeValue(currentNode, MINOCCURS ) != null ){
error = createError(currentNode, ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_CHOICE );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_CHOICE ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_SEQUENCE ) ){
if( Util.isInValidNodeName( currentNode, SEQUENCE ) ){
if( currentNode.isMaxoccursAttrExists() || Util.getAttributeValue(currentNode, MINOCCURS ) != null ){
error = createError(currentNode, ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_SEQUENCE );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( currentNode );
desc = Util.replaceWithNodeName( desc, REPLACE_ARG_0, surroundingType );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.MIN_AND_MAX_OCCURS_ARE_NOT_SUPPORTED_IN_SEQUENCE ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
return ;
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.ATTRIBUTE_NILLABLE_IS_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, ELEMENT ) && !Util.isRootNodeInSchema( currentNode ) ){
String nillable = Util.getAttributeValue(currentNode, NILLABLE );
if( nillable != null && (Boolean.parseBoolean(nillable) ) ){
error = createError(currentNode, ValidationRule.ATTRIBUTE_NILLABLE_IS_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, currentNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ATTRIBUTE_NILLABLE_IS_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.IDREF_AND_IDRE_FS_ARE_NOT_SUPPORTED ) ){
QName typeQName = null;
if( Util.isInValidNodeName( currentNode, ELEMENT ) || Util.isInValidNodeName( currentNode, ATTRIBUTE ) ){
typeQName = currentNode.getTypeAttrValue();
}else if( Util.isInValidNodeName( currentNode, RESTRICTION ) || Util.isInValidNodeName( currentNode, EXTENSION ) ){
typeQName = currentNode.getBaseAttrValue();
}else if( Util.isInValidNodeName( currentNode, LIST ) ){
typeQName = currentNode.getItemTypeAttrValue();
}
if( typeQName != null ){
String typeNameLocal = typeQName.getLocalPart();
if ( isValidInBuiltType( typeQName ) && (IDREF.equals(typeNameLocal) || IDREFS
.equals(typeNameLocal))){
error = createError(currentNode, ValidationRule.IDREF_AND_IDRE_FS_ARE_NOT_SUPPORTED );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.IDREF_AND_IDRE_FS_ARE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.ANY_TYPE_AND_ANY_SIMPLE_TYPE_NOT_SUPPORTED ) ){
QName typeQName = null;
if( Util.isInValidNodeName( currentNode, ELEMENT ) || Util.isInValidNodeName( currentNode, ATTRIBUTE ) ){
typeQName = currentNode.getTypeAttrValue();
}else if( Util.isInValidNodeName( currentNode, RESTRICTION ) || Util.isInValidNodeName( currentNode, EXTENSION ) ){
typeQName = currentNode.getBaseAttrValue();
}else if( Util.isInValidNodeName( currentNode, LIST ) ){
typeQName = currentNode.getItemTypeAttrValue();
}
if( typeQName != null ){
String typeNameLocal = typeQName.getLocalPart();
if ( isValidInBuiltType( typeQName ) &&
( ANYTYPE.equals(typeNameLocal) || ANYSIMPLETYPE.equals(typeNameLocal) ) ){
error = createError(currentNode, ValidationRule.ANY_TYPE_AND_ANY_SIMPLE_TYPE_NOT_SUPPORTED );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ANY_TYPE_AND_ANY_SIMPLE_TYPE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.MIXED_ATTRIBUTE_NOT_SUPPORTED ) ){
String typeName = null;
if( Util.isInValidNodeName( currentNode, COMPLEXTYPE ) ){
typeName = Util.getAttributeValue(currentNode, MIXED);
if( typeName != null && Boolean.parseBoolean(typeName)){
error = createError(currentNode, ValidationRule.MIXED_ATTRIBUTE_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, currentNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.MIXED_ATTRIBUTE_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.ATTRIBUTE_SUBSTITUTIONGROUP_IS_NOT_SUPPORTED ) ){
String typeName = null;
if( Util.isInValidNodeName( currentNode, ELEMENT ) ){
typeName = Util.getAttributeValue(currentNode, SUBSTITUTIONGROUP);
if( typeName != null ){
error = createError(currentNode, ValidationRule.ATTRIBUTE_SUBSTITUTIONGROUP_IS_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, currentNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ATTRIBUTE_SUBSTITUTIONGROUP_IS_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
if( m_rulesTobeValidated.contains( ValidationRule.UNBOUNDED_ELEMENT_WITH_TYPE_ID_IS_NOT_SUPPORTED ) ){
if( Util.isInValidNodeName( currentNode, ELEMENT ) && currentNode.isTypeAttrExists() ){
QName typeQName = currentNode.getTypeAttrValue();
if ( isValidInBuiltType( typeQName ) && ID.equals(typeQName.getLocalPart()) ){
String maxOcurs = currentNode.getMaxoccursAttrValue();
if( currentNode.isMaxoccursAttrExists() && ( UNBOUNDED.equals(maxOcurs) || Integer.valueOf(maxOcurs) > 1 )){
error = createError(currentNode, ValidationRule.UNBOUNDED_ELEMENT_WITH_TYPE_ID_IS_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, currentNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.UNBOUNDED_ELEMENT_WITH_TYPE_ID_IS_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
}
}
}
private boolean isValidInBuiltType(QName xsdType){
if( xsdType == null ){
return false;
}
return xsdType.getNamespaceURI().equals( WSDLParserConstants.NS_URI_2001_SCHEMA_XSD);
}
private void validatePolymorphism(SchemaNodeRepresentationByType typesMap){
//Test Polymorphism
List<SchemaNode> complexTypeNodes = typesMap.getSchemaNodesList(COMPLEXTYPE);
List<SchemaNode> elementNodes = typesMap.getSchemaNodesList( ELEMENT );
Map<QName, SchemaNode> abstractTypeMap = new HashMap<QName, SchemaNode>();
for( SchemaNode node : complexTypeNodes){
if( node.isAbstractAttrExists() && node.isAbstractAttrValue() && node.isNameAttrExists() ){
abstractTypeMap.put( new QName( node.getTargetNamespace(), node.getNameAttrValue() ), node );
}
}
for( SchemaNode node : elementNodes){
if( node.isTypeAttrExists() ){
QName typeQName = node.getTypeAttrValue();
SchemaNode abstractNode = abstractTypeMap.get(typeQName);
if(abstractNode != null){
FastSerFormatValidationError error = createError(node, ValidationRule.POLYMORPHISM_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, node );
desc = desc.replace(REPLACE_ARG_1, typeQName.getLocalPart() );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.POLYMORPHISM_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, node);
m_errors.add( error );
}
}
}
}
/**
* This method does validations for three rules.
* ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME
* TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME
* NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE
*
*
* @param currentNode
* @param mapOfAllTypes
*/
private void validateAttributeAndElementName(SchemaNode currentNode, SchemaNodeRepresentationByType typesMap ){
//This map collects all the attribute nodes defined in the complex type.
//If two attributes have same name then it is overwritten.
Map<String, SchemaNode> mapOfAttributes = new HashMap<String, SchemaNode>();
//This map collects all the element nodes defined in the complex type.
//The validation for duplicate element name (TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME)
//is aggressive i.e. while traversing validation takes place
Map<String, SchemaNode> mapOfElements = new HashMap<String, SchemaNode>();
//If any of the complex type extends a used defined simple type or inbuilt xsd type
//it is invalid NAME_OF_ELEMENT_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE
Map<QName, SchemaNode> baseType2ComplexTypeMap = new HashMap<QName, SchemaNode>();
recursivelyPopulateAndvalidateName( currentNode, typesMap, mapOfAttributes, mapOfElements, baseType2ComplexTypeMap);
//validate for NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE
//size cannot be more than one
if( m_rulesTobeValidated.contains( ValidationRule.NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE ) ){
if( baseType2ComplexTypeMap.size() == 1 && mapOfAttributes.containsKey( VALUE ) ){
FastSerFormatValidationError error = createError(currentNode, ValidationRule.NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, currentNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE ) );
error.setDescription(desc);
log(error, currentNode);
m_errors.add( error );
}
}
//validate attribute names
//If any of the attribute name is same as the element name then throw error ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME
if( m_rulesTobeValidated.contains( ValidationRule.ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME ) ){
for( Map.Entry<String, SchemaNode> entry : mapOfAttributes.entrySet() ){
String attributeName = entry.getKey();
SchemaNode attr = entry.getValue();
//same name but different case is also not supported
SchemaNode elemen = mapOfElements.get(attributeName.toLowerCase());
if( elemen != null ){
FastSerFormatValidationError error = createError(attr, ValidationRule.ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME );
String desc = error.getDescription();
desc = desc.replace(REPLACE_ARG_0, attributeName);
SchemaNode surroundingType = Util.getSurroundingType( elemen );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME ) );
error.setDescription(desc);
log(error, surroundingType);
m_errors.add( error );
}
}
}
}
/**
* This method is called if two element have same name in the same hierarchy.
* Creates error ValidationRule.TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME
*
* @param oldElement
* @param newElement
*/
private void handleDuplicateElementName(SchemaNode oldElement, SchemaNode newElement, String name){
if( !m_rulesTobeValidated.contains( ValidationRule.TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME ) ){
return ;
}
FastSerFormatValidationError error = createError(newElement, ValidationRule.TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME );
String desc = error.getDescription();
SchemaNode surroundingType = Util.getSurroundingType( oldElement );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, surroundingType );
surroundingType = Util.getSurroundingType( newElement );
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_1, surroundingType );
desc = desc.replace(REPLACE_ARG_3, name );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME ) );
error.setDescription(desc);
log(error, surroundingType);
m_errors.add( error );
}
/**
* This method is called if the current node is restriction or extension as restriction and extension would have base attribute.
* If the base type is user defined simple type or inbuilt type then argument baseType2ComplexTypeMap is filled.
* This map would be used later for rule NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE
*
* If the base type is complex type, recursivelyPopulateAndvalidateName is called.
*
* @param currentNode
* @param mapOfAllTypes
* @param mapOfAttributes
* @param mapOfElements
* @param baseType2ComplexTypeMap
*/
private void handleBaseTypes(SchemaNode currentNode,
SchemaNodeRepresentationByType typesMap,
Map<String, SchemaNode> mapOfAttributes,
Map<String, SchemaNode> mapOfElements,
Map<QName, SchemaNode> baseType2ComplexTypeMap) {
if( currentNode.isBaseAttrExists() ){
QName typeQName = currentNode.getBaseAttrValue();
SchemaNode baseType = typesMap.getType(typeQName);// mapOfAllTypes.get(typeQName);
if (baseType != null
&& baseType.getNodeName().equals(COMPLEXTYPE)) {
recursivelyPopulateAndvalidateName(baseType, typesMap,
mapOfAttributes, mapOfElements,
baseType2ComplexTypeMap);
} else {
boolean userDefinedSimpleType = false;
boolean xsdType = typeQName.getNamespaceURI().equals(
WSDLParserConstants.NS_URI_2001_SCHEMA_XSD);
if (!xsdType && baseType != null) {
userDefinedSimpleType = baseType.getNodeName().equals(
SIMPLETYPE);
}
if (xsdType || userDefinedSimpleType) {
baseType2ComplexTypeMap.put(typeQName,
Util.getSurroundingType(currentNode));
}
}
}
}
/**
* If the node passed is of element type, the method updates map mapOfElements.
* If the node passed is of attribute type, the method updates map mapOfAttributes.
* If the node passed is of restriction or extension, the method calls handleBaseTypes to populate
* mapOfElements and mapOfAttributes
*
* For each child node, it calls recursively the same method to populate the names.
* If duplicate field names are encountered, error TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME is thrown.
*
* @param currentNode
* @param mapOfAllTypes
* @param mapOfAttributes
* @param mapOfElements
* @param baseType2ComplexTypeMap
*/
private void recursivelyPopulateAndvalidateName(SchemaNode currentNode,
SchemaNodeRepresentationByType typesMap,
Map<String, SchemaNode> mapOfAttributes,
Map<String, SchemaNode> mapOfElements,
Map<QName, SchemaNode> baseType2ComplexTypeMap) {
if( Util.isInValidNodeName( currentNode, RESTRICTION ) ){
handleBaseTypes( currentNode, typesMap, mapOfAttributes, mapOfElements, baseType2ComplexTypeMap );
//if it is a restriction, then return immediately after handling base type.
//since it is a restricted complex type, the element name defined inside restriction would be same
//as element names defined in base type.
return ;
}else if( Util.isInValidNodeName( currentNode, EXTENSION ) ){
handleBaseTypes( currentNode, typesMap, mapOfAttributes, mapOfElements, baseType2ComplexTypeMap );
}else if( Util.isInValidNodeName( currentNode, ELEMENT ) ){
SchemaNode elementNode = currentNode;
if( !elementNode.isNameAttrExists() && elementNode.isRefAttrExists() ){
QName refQName = currentNode.getRefAttrValue();
elementNode = typesMap.getRootElementNode(refQName);
}
if(elementNode != null ){
String nameAttribute = elementNode.getNameAttrValue();
//same name but different case is also not supported
SchemaNode oldElement = mapOfElements.put(nameAttribute.toLowerCase(), elementNode);
//if it is not null, then there are two elements with same name
if( oldElement != null ){
handleDuplicateElementName(oldElement, elementNode, nameAttribute);
}
}
}else if( Util.isInValidNodeName( currentNode, ATTRIBUTE ) ){
if( currentNode.isNameAttrExists() ){
//same name but different case is also not supported
mapOfAttributes.put(currentNode.getNameAttrValue().toLowerCase() , currentNode);
}
}else if( Util.isInValidNodeName( currentNode, ATTRIBUTE_GROUP ) || Util.isInValidNodeName( currentNode, GROUP ) ){
boolean isAttrGroup = Util.isInValidNodeName( currentNode, ATTRIBUTE_GROUP );
if( currentNode.isRefAttrExists() ){
QName refQName = currentNode.getRefAttrValue();
SchemaNode refNode = null;
if(isAttrGroup){
refNode = typesMap.getRootAttributeGroupNode(refQName);
}else{
refNode = typesMap.getRootGroupNode(refQName);
}
if( refNode != null ){
recursivelyPopulateAndvalidateName(refNode, typesMap, mapOfAttributes, mapOfElements, baseType2ComplexTypeMap);
}
}
}
List<SchemaNode> childNodes = currentNode.getChildNodes();
for( SchemaNode child : childNodes ){
recursivelyPopulateAndvalidateName( child, typesMap, mapOfAttributes, mapOfElements, baseType2ComplexTypeMap);
}
}
/**
* This method does validations for threee rules.
* ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME
* TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME
* NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE
*
*/
private void validateDuplicateFieldNames(SchemaNodeRepresentationByType typesMap ){
List<SchemaNode> complexTypeNodes = typesMap.getComplexTypeNodes();
for( SchemaNode node : complexTypeNodes ){
validateAttributeAndElementName( node, typesMap );
}
}
/**
* This method validates following structure.
*
* <xs:simpleType name="MySimpleTypeListA">
* <xs:restriction base="tns:MySimpleTypeList"></xs:restriction>
* </xs:simpleType>
* <xs:simpleType name="MySimpleTypeList">
* <xs:list itemType="xs:double" />
* </xs:simpleType>
*
* <xs:element minOccurs="0" maxOccurs="unbounded" name="param5"
* type="tns:MySimpleTypeListA" />
*
* The jaxb generates type as List<JAXBElement<List<Double>>> param5
*
* This is not supported by protobuf
*
* @param allSimpleTypeNodes
* @param allElementNodes
*/
private void validateListOfList( SchemaNodeRepresentationByType typesMap ){
List<SchemaNode> allElementNodes = typesMap.getSchemaNodesList( ELEMENT );
List<SchemaNode> listNodes = typesMap.getSchemaNodesList(LIST);
List<SchemaNode> restrctionNodes = typesMap.getSchemaNodesList(RESTRICTION);
//contains all the simple types that has list nodes
Map<QName,SchemaNode> listSimpleTypeNodesMap = new HashMap<QName,SchemaNode>();
//maps the restriction base type name to its simple type name
//e.g.
/**
* <xs:simpleType name="MySimpleTypeListA">
* <xs:restriction base="tns:MySimpleTypeList"></xs:restriction>
* </xs:simpleType>
*/
Map<QName, List<QName> > restrictionBase2NameMap = new HashMap<QName, List<QName> >();
//contains the final set of simple types which element should not use as unbounded
Set<QName> derivedListUsers = new HashSet<QName>();
populateListSimpleTypeNodesMap(listNodes, listSimpleTypeNodesMap);
if( listSimpleTypeNodesMap.size() == 0 ){
//if no list tag just return
return ;
}
derivedListUsers.addAll( listSimpleTypeNodesMap.keySet() );
populateRestrictionBase2NameMap(restrctionNodes, restrictionBase2NameMap);
if( restrictionBase2NameMap.size() > 0 ){
for( Map.Entry<QName, SchemaNode> entry : listSimpleTypeNodesMap.entrySet() ){
QName baseType = entry.getKey();
//find out recursively consider the example given in comments
//a simple type can have another simple type as restriction.
//this can go n level deep
recursivelyFindOutAllSimpleTypesThatUsesList( baseType, restrictionBase2NameMap, derivedListUsers );
}
}
for( SchemaNode elementNode : allElementNodes ){
String maxOcurs = elementNode.getMaxoccursAttrValue();
if( elementNode.isMaxoccursAttrExists() && ( UNBOUNDED.equals(maxOcurs) || Integer.valueOf(maxOcurs) > 1 )){
if( elementNode.isTypeAttrExists() && derivedListUsers.contains(elementNode.getTypeAttrValue() ) ){
FastSerFormatValidationError error = createError(elementNode, ValidationRule.UNBOUNDED_SIMPLE_TYPE_WITH_LIST_NOT_SUPPORTED );
String desc = error.getDescription();
desc = Util.replaceWithNameAttribute( desc, REPLACE_ARG_0, elementNode );
desc = desc.replace(REPLACE_ARG_2, getSupportedTypesString( ValidationRule.UNBOUNDED_SIMPLE_TYPE_WITH_LIST_NOT_SUPPORTED ) );
error.setDescription(desc);
log(error, elementNode);
m_errors.add( error );
}
}
}
}
private void recursivelyFindOutAllSimpleTypesThatUsesList(QName baseType,
Map<QName, List<QName>> restrictionBase2NameMap,
Set<QName> derivedListUsers) {
List<QName> simpleTypeNames = restrictionBase2NameMap.get( baseType );
if( simpleTypeNames == null ){
simpleTypeNames = new ArrayList<QName>();
}
derivedListUsers.addAll(simpleTypeNames);
for( QName simpleTypeName : simpleTypeNames ){
recursivelyFindOutAllSimpleTypesThatUsesList(simpleTypeName, restrictionBase2NameMap, derivedListUsers);
}
}
private void populateListSimpleTypeNodesMap(List<SchemaNode> listNodes, Map<QName,SchemaNode> listSimpleTypeNodesMap){
for( SchemaNode node : listNodes ){
SchemaNode surroundingNode = Util.getSurroundingType(node);
if( Util.isInValidNodeName(surroundingNode, SIMPLETYPE)){
//may be an anonymous type
if( surroundingNode.isNameAttrExists() ){
QName typeName = new QName( surroundingNode.getTargetNamespace(), surroundingNode.getNameAttrValue() );
listSimpleTypeNodesMap.put(typeName, surroundingNode);
}
}
}
}
private void populateRestrictionBase2NameMap(List<SchemaNode> restrctionNodes, Map<QName, List<QName> > restrictionBase2NameMap){
for( SchemaNode node : restrctionNodes ){
SchemaNode surroundingNode = Util.getSurroundingType(node);
if( Util.isInValidNodeName(surroundingNode, SIMPLETYPE)){
//may be an anonymous type
if( surroundingNode.isNameAttrExists() && node.isBaseAttrExists() ){
QName baseTypeName = node.getBaseAttrValue();
//we are interested in user defined types
if( isValidInBuiltType(baseTypeName) ){
continue;
}
QName typeName = new QName( surroundingNode.getTargetNamespace(), surroundingNode.getNameAttrValue() );
List<QName> listOfTypes = restrictionBase2NameMap.get( baseTypeName );
if( listOfTypes == null ){
listOfTypes = new ArrayList<QName>();
restrictionBase2NameMap.put( baseTypeName, listOfTypes );
}
listOfTypes.add(typeName);
}
}
}
}
private void doOtherValidations(){
if( m_rulesTobeValidated.contains( ValidationRule.POLYMORPHISM_NOT_SUPPORTED ) ){
validatePolymorphism( m_typesMap );
}
if( m_rulesTobeValidated.contains( ValidationRule.ATTRIBUTE_NAME_CANNOT_BE_SAME_AS_FIELD_NAME )
|| m_rulesTobeValidated.contains( ValidationRule.TWO_ELEMENTS_CANNOT_HAVE_SAME_NAME )
|| m_rulesTobeValidated.contains( ValidationRule.NAME_OF_ATTRIBUTE_CANNOT_BE_VALUE_WHEN_EXTENDING_SIMPLE_TYPE ) ){
validateDuplicateFieldNames( m_typesMap);
}
if( m_rulesTobeValidated.contains( ValidationRule.UNBOUNDED_SIMPLE_TYPE_WITH_LIST_NOT_SUPPORTED ) ){
validateListOfList( m_typesMap );
}
}
private boolean isValidURL( String filePath ){
try {
new URL( filePath );
return true;
} catch (MalformedURLException e) {
getLogger().log(Level.SEVERE, "The file path passed is not a valid URL."+filePath);
getLogger().log(Level.SEVERE, "The file path passed is not a valid URL."+e.getMessage());
return false;
}
}
/**
* This method validates one or more files.
* The file can be wsdl file or xsd file.
*
* @param files
* @return
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
public List<FastSerFormatValidationError> validateFile(String... files) throws CodeGenFailedException{
long startTime = System.currentTimeMillis();
LocatorImpl sourceLocator = new LocatorImpl();
SchemaParserEventHandler handler = new SchemaParserEventHandler( this, m_rootNode, m_typesMap );
handler.setDocumentLocator(sourceLocator);
for( int i=0; i<files.length; i++ ){
String filePath = files[i];
File file = new File( filePath );
InputStream stream = null;
getLogger().log(Level.INFO, "Start loading file " + filePath);
try{
if( file.exists() ){
stream = new FileInputStream( file );
getLogger().log(Level.INFO, "File path exists");
}else if( isValidURL( filePath ) ){
//path of a jar. expected format is 'jar:file:\C:....\xyz.jar!\...\abc.xsd'
URL filePathUrl = new URL( filePath );
stream = filePathUrl.openStream();
}else{
getLogger().log(Level.INFO, "File path does not exists. Try to load file using getResourceAsStream");
stream = CodeGenUtil.getInputStreamForAFileFromClasspath(filePath, getClass().getClassLoader() );
if( stream == null ){
getLogger().log(Level.SEVERE, "File not found. Path = " + filePath);
throw new CodeGenFailedException("File not found. Path = " + filePath );
}
}
InputSource is = new InputSource( stream );
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(handler);
reader.setErrorHandler(handler);
handler.setFileName( file.getAbsolutePath() );
reader.parse( is );
}catch(CodeGenFailedException e){
throw e;
}catch(Exception e){
throw new CodeGenFailedException("File Parsing Failed." + e.getMessage(), e );
}finally{
if( stream != null){
try {
stream.close();
} catch (Exception e) {
getLogger().log(Level.WARNING, "Unable to close the wsdl file");
}
}
}
}
doOtherValidations();
long endTime = System.currentTimeMillis();
getLogger().log(Level.INFO, "The time take to do parsing and perform all validations "+ (endTime-startTime) +" msecs");
return m_errors;
}
/**
* This method validates one single wsdl file.
*
* @param wsdlFile
* @param supportedFormats
* @throws CodeGenFailedException
*/
public static void validateWSDL(String wsdlFileLoc, List<FastSerFormatType> supportedFormats) throws CodeGenFailedException{
FastSerFormatValidationHandler handler = new FastSerFormatValidationHandler( supportedFormats );
try {
List<FastSerFormatValidationError> errors = handler.validateFile( wsdlFileLoc );
if( errors.size() > 0 ){
String msg = "The WSDL is invalid to support Fast Ser Formats like " + supportedFormats.toString();
throw new FastSerFormatNotSupportedException(msg, errors );
}
}catch (FastSerFormatNotSupportedException e ){
throw e;
}catch (CodeGenFailedException e){
throw e;
}catch (Exception e) {
throw new CodeGenFailedException("Validation of the WSDL failed.", e);
}
}
/**
* This method validates the wsdl against unsupported constructs for fast ser format.
*
* @param context
* @param supportedFormats
* @throws CodeGenFailedException
*/
public static void validateServiceForFastSerFormatSupport(CodeGenContext context, List<FastSerFormatType> supportedFormats) throws CodeGenFailedException{
InputOptions inputOptions = context.getInputOptions();
String wsdlFileLoc = inputOptions.getInputFile();
if( wsdlFileLoc == null ){
getLogger().warning("Validation Not done. The path of the wsdl is empty.");
throw new CodeGenFailedException( EMPTY_WSDL_PATH );
}
validateWSDL( wsdlFileLoc, supportedFormats);
}
/**
* This method validates list of xsd files.
*
* @param xsdFileNames
* @param baseXsdPath
* @param supportedFormats
* @throws CodeGenFailedException
*/
public static void validateXsds(String[] xsdFileNames, List<FastSerFormatType> supportedFormats) throws CodeGenFailedException{
FastSerFormatValidationHandler handler = new FastSerFormatValidationHandler( supportedFormats );
try {
List<FastSerFormatValidationError> errors = handler.validateFile( xsdFileNames );
if( errors.size() > 0 ){
String msg = "One or more XSD files are invalid to support Fast Ser Formats like " + supportedFormats.toString();
throw new FastSerFormatNotSupportedException(msg, errors );
}
}catch (FastSerFormatNotSupportedException e ){
throw e;
}catch (CodeGenFailedException e){
throw e;
}catch (Exception e) {
throw new CodeGenFailedException("Validation of the WSDL failed.", e);
}
}
public static class Util {
/**
* Checks whether the given node contains name same as the node name.
*
* @param currentNode
* @param nodeName
* @return
*/
public static boolean isInValidNodeName(SchemaNode currentNode, String... nodeNames ){
for(String nodeName : nodeNames ){
if(nodeName.equals( currentNode.getNodeName() ) ){
return true;
}
}
return false;
}
/**
* Returns the value of the specified attribute.
* Returns null if the attribute is not found.
*
* @param attrs
* @param attributeName
* @return
*/
public static String getAttributeValue(List<SchemaNodeAttribute> attrs, String attributeName){
for( SchemaNodeAttribute attr : attrs ){
if( attributeName.equals(attr.getAttributeName()) ){
return attr.getAttributeValue();
}
}
return null;
}
/**
* This method returns the value of the specified attribute name.
* This method is fail safe which checks not null for node.
* Returns null if the node is null or attribute is not found.
*
* @param node
* @param attributeName
* @return
*/
public static String getAttributeValue(SchemaNode node, String attributeName){
if( node == null ){
return null;
}
return getAttributeValue(node.getAttributes(), attributeName );
}
/**
* This method identifies the surrounding type of the specified node.
* The surrounding type returned would be either Complex type, Simple Type,
* Group or attribute group.
* This method is used to build user friendly error message.
*
* @param node
* @return
*/
public static SchemaNode getSurroundingType( SchemaNode node ){
SchemaNode parent = node.getParentNode();
while (parent != null){
String parentNodename = parent.getNodeName();
if(COMPLEXTYPE.equals(parentNodename) ||
SIMPLETYPE.equals(parentNodename) ||
GROUP.equals(parentNodename) ||
ATTRIBUTE_GROUP.equals(parentNodename) ){
return parent;
}
parent = parent.getParentNode();
}
return null;
}
/**
* This method identifies the surrounding element of the specified node.
*
* @param node
* @return
*/
public static SchemaNode getSurroundingElement( SchemaNode node ){
SchemaNode parent = node.getParentNode();
while (parent != null){
String parentNodename = parent.getNodeName();
if(ELEMENT.equals(parentNodename) ){
return parent;
}
parent = parent.getParentNode();
}
return null;
}
/**
* If the root element node which is directly under schema tag then return true;
*
* @param currentNode
* @return
*/
public static boolean isRootNodeInSchema( SchemaNode currentNode ){
if( currentNode.getParentNode() != null){
if( SCHEMA.equals( currentNode.getParentNode().getNodeName() ) ){
//this is because if the element is at root level directly inside schema node then dont validate
return true;
}
}
return false;
}
public static String replaceWithNodeName(String templateToSearch, String searchString, SchemaNode node){
templateToSearch = templateToSearch.replace(searchString, ( node!=null ) ? node.getNodeName() : EMPTY_STRING);
return templateToSearch;
}
public static String replaceWithNameAttribute(String templateToSearch, String searchString, SchemaNode node){
String nameAttribute = EMPTY_STRING;
if( node != null && node.isNameAttrExists()){
nameAttribute = node.getNameAttrValue();
}
templateToSearch = templateToSearch.replace(searchString, nameAttribute );
return templateToSearch;
}
}
}