/*
 *  soapUI, copyright (C) 2004-2012 smartbear.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.impl.wsdl.support.xsd;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaAnnotation;
import org.apache.xmlbeans.SchemaField;
import org.apache.xmlbeans.SchemaLocalElement;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.SimpleValue;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlBase64Binary;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlHexBinary;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.SoapUIExtensionClassLoader;
import com.eviware.soapui.SoapUIExtensionClassLoader.SoapUIClassLoaderState;
import com.eviware.soapui.impl.wsdl.support.Constants;
import com.eviware.soapui.model.settings.SettingsListener;
import com.eviware.soapui.settings.WsdlSettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.Tools;
import com.eviware.soapui.support.xml.XmlUtils;

/**
 * XML-Schema related tools
 * 
 * @author Ole.Matzura
 */

public class SchemaUtils
{
	private final static Logger log = Logger.getLogger( SchemaUtils.class );
	private static Map<String, XmlObject> defaultSchemas = new HashMap<String, XmlObject>();

	static
	{
		initDefaultSchemas();

		SoapUI.getSettings().addSettingsListener( new SettingsListener()
		{

			public void settingChanged( String name, String newValue, String oldValue )
			{
				if( name.equals( WsdlSettings.SCHEMA_DIRECTORY ) )
				{
					log.info( "Reloading default schemas.." );
					initDefaultSchemas();
				}
			}

			@Override
			public void settingsReloaded()
			{
				// TODO Auto-generated method stub

			}
		} );
	}

	public static void initDefaultSchemas()
	{
		SoapUIClassLoaderState state = SoapUIExtensionClassLoader.ensure();

		try
		{
			defaultSchemas.clear();

			String root = "/com/eviware/soapui/resources/xsds";

			loadDefaultSchema( SoapUI.class.getResource( root + "/xop.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/XMLSchema.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/xml.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/swaref.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/xmime200505.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/xmime200411.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/soapEnvelope.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/soapEncoding.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/soapEnvelope12.xsd" ) );
			loadDefaultSchema( SoapUI.class.getResource( root + "/soapEncoding12.xsd" ) );

			String schemaDirectory = SoapUI.getSettings().getString( WsdlSettings.SCHEMA_DIRECTORY, null );
			if( StringUtils.hasContent( schemaDirectory ) )
				loadSchemaDirectory( schemaDirectory );
		}
		catch( Exception e )
		{
			SoapUI.logError( e );
		}
		finally
		{
			state.restore();
		}
	}

	private static void loadSchemaDirectory( String schemaDirectory ) throws IOException, MalformedURLException
	{
		File dir = new File( schemaDirectory );
		if( dir.exists() && dir.isDirectory() )
		{
			String[] xsdFiles = dir.list();
			int cnt = 0;

			if( xsdFiles != null && xsdFiles.length > 0 )
			{
				for( int c = 0; c < xsdFiles.length; c++ )
				{
					try
					{
						String xsdFile = xsdFiles[c];
						if( xsdFile.endsWith( ".xsd" ) )
						{
							String filename = schemaDirectory + File.separator + xsdFile;
							loadDefaultSchema( new URL( "file:" + filename ) );
							cnt++ ;
						}
					}
					catch( Throwable e )
					{
						SoapUI.logError( e );
					}
				}
			}

			if( cnt == 0 )
				log.warn( "Missing schema files in  schemaDirectory [" + schemaDirectory + "]" );
		}
		else
			log.warn( "Failed to open schemaDirectory [" + schemaDirectory + "]" );
	}

	private static void loadDefaultSchema( URL url ) throws Exception
	{
		// XmlObject xmlObject = XmlObject.Factory.parse( url );
		XmlObject xmlObject = XmlUtils.createXmlObject( url );
		if( !( ( Document )xmlObject.getDomNode() ).getDocumentElement().getNamespaceURI().equals( Constants.XSD_NS ) )
			return;

		String targetNamespace = getTargetNamespace( xmlObject );

		if( defaultSchemas.containsKey( targetNamespace ) )
			log.warn( "Overriding schema for targetNamespace " + targetNamespace );

		defaultSchemas.put( targetNamespace, xmlObject );

		log.info( "Added default schema from " + url.getPath() + " with targetNamespace " + targetNamespace );
	}

	public static SchemaTypeSystem loadSchemaTypes( String wsdlUrl, SchemaLoader loader ) throws SchemaException
	{
		SoapUIClassLoaderState state = SoapUIExtensionClassLoader.ensure();

		try
		{
			log.info( "Loading schema types from [" + wsdlUrl + "]" );
			ArrayList<XmlObject> schemas = new ArrayList<XmlObject>( getSchemas( wsdlUrl, loader ).values() );

			return buildSchemaTypes( schemas );
		}
		catch( Exception e )
		{
			SoapUI.logError( e );
			if( e instanceof SchemaException )
				throw ( SchemaException )e;
			else
				throw new SchemaException( "Error loading schema types", e );
		}
		finally
		{
			state.restore();
		}
	}

	public static SchemaTypeSystem buildSchemaTypes( List<XmlObject> schemas ) throws SchemaException
	{
		XmlOptions options = new XmlOptions();
		options.setCompileNoValidation();
		options.setCompileNoPvrRule();
		options.setCompileDownloadUrls();
		options.setCompileNoUpaRule();
		options.setValidateTreatLaxAsSkip();

		for( int c = 0; c < schemas.size(); c++ )
		{
			XmlObject xmlObject = schemas.get( c );
			if( xmlObject == null
					|| !( ( Document )xmlObject.getDomNode() ).getDocumentElement().getNamespaceURI()
							.equals( Constants.XSD_NS ) )
			{
				schemas.remove( c );
				c-- ;
			}
		}

		boolean strictSchemaTypes = SoapUI.getSettings().getBoolean( WsdlSettings.STRICT_SCHEMA_TYPES );
		if( !strictSchemaTypes )
		{
			Set<String> mdefNamespaces = new HashSet<String>();

			for( XmlObject xObj : schemas )
			{
				mdefNamespaces.add( getTargetNamespace( xObj ) );
			}

			options.setCompileMdefNamespaces( mdefNamespaces );
		}

		ArrayList<?> errorList = new ArrayList<Object>();
		options.setErrorListener( errorList );

		XmlCursor cursor = null;

		try
		{
			// remove imports
			for( int c = 0; c < schemas.size(); c++ )
			{
				XmlObject s = schemas.get( c );

				Map<?, ?> map = new HashMap<String, String>();
				cursor = s.newCursor();
				cursor.toStartDoc();
				if( toNextContainer( cursor ) )
					cursor.getAllNamespaces( map );
				else
					log.warn( "Can not get namespaces for " + s );

				String tns = getTargetNamespace( s );

				// log.info( "schema for [" + tns + "] contained [" + map.toString()
				// + "] namespaces" );

				if( strictSchemaTypes && defaultSchemas.containsKey( tns ) )
				{
					schemas.remove( c );
					c-- ;
				}
				else
				{
					removeImports( s );
				}

				cursor.dispose();
				cursor = null;
			}

			// schemas.add( soapVersion.getSoapEncodingSchema());
			// schemas.add( soapVersion.getSoapEnvelopeSchema());
			schemas.addAll( defaultSchemas.values() );

			SchemaTypeSystem sts = XmlBeans.compileXsd( schemas.toArray( new XmlObject[schemas.size()] ),
					XmlBeans.getBuiltinTypeSystem(), options );

			return sts;
			// return XmlBeans.typeLoaderUnion(new SchemaTypeLoader[] { sts,
			// XmlBeans.getBuiltinTypeSystem() });
		}
		catch( Exception e )
		{
			SoapUI.logError( e );
			throw new SchemaException( e, errorList );
		}
		finally
		{
			for( int c = 0; c < errorList.size(); c++ )
			{
				log.warn( "Error: " + errorList.get( c ) );
			}

			if( cursor != null )
				cursor.dispose();
		}
	}

	public static boolean toNextContainer( XmlCursor cursor )
	{
		while( !cursor.isContainer() && !cursor.isEnddoc() )
			cursor.toNextToken();

		return cursor.isContainer();
	}

	public static String getTargetNamespace( XmlObject s )
	{
		return ( ( Document )s.getDomNode() ).getDocumentElement().getAttribute( "targetNamespace" );
	}

	public static Map<String, XmlObject> getSchemas( String wsdlUrl, SchemaLoader loader ) throws SchemaException
	{
		Map<String, XmlObject> result = new HashMap<String, XmlObject>();
		getSchemas( wsdlUrl, result, loader, null /* , false */);
		return result;
	}

	/**
	 * Returns a map mapping urls to corresponding XmlSchema XmlObjects for the
	 * specified wsdlUrl
	 */

	public static void getSchemas( String wsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader, String tns )
			throws SchemaException
	{

		if( existing.containsKey( wsdlUrl ) )
		{
			return;
		}

		// if( add )
		// existing.put( wsdlUrl, null );

		log.info( "Getting schema " + wsdlUrl );

		ArrayList<?> errorList = new ArrayList<Object>();

		Map<String, XmlObject> result = new HashMap<String, XmlObject>();

		boolean common = false;

		try
		{
			XmlOptions options = new XmlOptions();
			options.setCompileNoValidation();
			options.setSaveUseOpenFrag();
			options.setErrorListener( errorList );
			options.setSaveSyntheticDocumentElement( new QName( Constants.XSD_NS, "schema" ) );

			XmlObject xmlObject = loader.loadXmlObject( wsdlUrl, options );
			if( xmlObject == null )
				throw new Exception( "Failed to load schema from [" + wsdlUrl + "]" );

			Document dom = ( Document )xmlObject.getDomNode();
			Node domNode = dom.getDocumentElement();

			// is this an xml schema?
			if( domNode.getLocalName().equals( "schema" ) && Constants.XSD_NS.equals( domNode.getNamespaceURI() ) )
			{
				// set targetNamespace (this happens if we are following an include
				// statement)
				if( tns != null )
				{
					Element elm = ( ( Element )domNode );
					if( !elm.hasAttribute( "targetNamespace" ) )
					{
						common = true;
						elm.setAttribute( "targetNamespace", tns );
					}

					// check for namespace prefix for targetNamespace
					NamedNodeMap attributes = elm.getAttributes();
					int c = 0;
					for( ; c < attributes.getLength(); c++ )
					{
						Node item = attributes.item( c );
						if( item.getNodeName().equals( "xmlns" ) )
							break;

						if( item.getNodeValue().equals( tns ) && item.getNodeName().startsWith( "xmlns" ) )
							break;
					}

					if( c == attributes.getLength() )
						elm.setAttribute( "xmlns", tns );
				}

				if( common && !existing.containsKey( wsdlUrl + "@" + tns ) )
					result.put( wsdlUrl + "@" + tns, xmlObject );
				else
					result.put( wsdlUrl, xmlObject );
			}
			else
			{
				existing.put( wsdlUrl, null );

				XmlObject[] paths = xmlObject.selectPath( "declare namespace s='" + Constants.XSD_NS + "' .//s:schema" );

				for( int i = 0; i < paths.length; i++ )
				{
					XmlCursor xmlCursor = paths[i].newCursor();
					String xmlText = xmlCursor.getObject().xmlText( options );

					XmlObject obj = XmlUtils.createXmlObject( xmlText, new XmlOptions() );
					obj.documentProperties().setSourceName( wsdlUrl );

					result.put( wsdlUrl + "@" + ( i + 1 ), obj );
				}

				XmlObject[] wsdlImports = xmlObject.selectPath( "declare namespace s='" + Constants.WSDL11_NS
						+ "' .//s:import/@location" );
				for( int i = 0; i < wsdlImports.length; i++ )
				{
					String location = ( ( SimpleValue )wsdlImports[i] ).getStringValue();
					if( location != null )
					{
						if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
							location = Tools.joinRelativeUrl( wsdlUrl, location );

						getSchemas( location, existing, loader, null );
					}
				}

				XmlObject[] wadl10Imports = xmlObject.selectPath( "declare namespace s='" + Constants.WADL10_NS
						+ "' .//s:grammars/s:include/@href" );
				for( int i = 0; i < wadl10Imports.length; i++ )
				{
					String location = ( ( SimpleValue )wadl10Imports[i] ).getStringValue();
					if( location != null )
					{
						if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
							location = Tools.joinRelativeUrl( wsdlUrl, location );

						getSchemas( location, existing, loader, null );
					}
				}

				XmlObject[] wadlImports = xmlObject.selectPath( "declare namespace s='" + Constants.WADL11_NS
						+ "' .//s:grammars/s:include/@href" );
				for( int i = 0; i < wadlImports.length; i++ )
				{
					String location = ( ( SimpleValue )wadlImports[i] ).getStringValue();
					if( location != null )
					{
						if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
							location = Tools.joinRelativeUrl( wsdlUrl, location );

						getSchemas( location, existing, loader, null );
					}
				}

			}

			existing.putAll( result );

			XmlObject[] schemas = result.values().toArray( new XmlObject[result.size()] );

			for( int c = 0; c < schemas.length; c++ )
			{
				xmlObject = schemas[c];

				XmlObject[] schemaImports = xmlObject.selectPath( "declare namespace s='" + Constants.XSD_NS
						+ "' .//s:import/@schemaLocation" );
				for( int i = 0; i < schemaImports.length; i++ )
				{
					String location = ( ( SimpleValue )schemaImports[i] ).getStringValue();
					Element elm = ( ( Attr )schemaImports[i].getDomNode() ).getOwnerElement();

					if( location != null && !defaultSchemas.containsKey( elm.getAttribute( "namespace" ) ) )
					{
						if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
							location = Tools.joinRelativeUrl( wsdlUrl, location );

						getSchemas( location, existing, loader, null );
					}
				}

				XmlObject[] schemaIncludes = xmlObject.selectPath( "declare namespace s='" + Constants.XSD_NS
						+ "' .//s:include/@schemaLocation" );
				for( int i = 0; i < schemaIncludes.length; i++ )
				{
					String location = ( ( SimpleValue )schemaIncludes[i] ).getStringValue();
					if( location != null )
					{
						String targetNS = getTargetNamespace( xmlObject );

						if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
							location = Tools.joinRelativeUrl( wsdlUrl, location );

						getSchemas( location, existing, loader, targetNS );
					}
				}
			}
		}
		catch( Exception e )
		{
			SoapUI.logError( e );
			throw new SchemaException( e, errorList );
		}
	}

	/**
	 * Returns a map mapping urls to corresponding XmlObjects for the specified
	 * wsdlUrl
	 */

	public static Map<String, XmlObject> getDefinitionParts( SchemaLoader loader ) throws Exception
	{
		Map<String, XmlObject> result = new LinkedHashMap<String, XmlObject>();
		getDefinitionParts( loader.getBaseURI(), result, loader );
		return result;
	}

	public static void getDefinitionParts( String origWsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader )
			throws Exception
	{
		String wsdlUrl = origWsdlUrl;
		if( existing.containsKey( wsdlUrl ) )
			return;

		XmlObject xmlObject = loader.loadXmlObject( wsdlUrl, null );
		existing.put( wsdlUrl, xmlObject );
		// wsdlUrl = loader.getBaseURI();

		selectDefinitionParts( wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WSDL11_NS
				+ "' .//s:import/@location" );
		selectDefinitionParts( wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WADL10_NS
				+ "' .//s:grammars/s:include/@href" );
		selectDefinitionParts( wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WADL11_NS
				+ "' .//s:grammars/s:include/@href" );
		selectDefinitionParts( wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.XSD_NS
				+ "' .//s:import/@schemaLocation" );
		selectDefinitionParts( wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.XSD_NS
				+ "' .//s:include/@schemaLocation" );
	}

	private static void selectDefinitionParts( String wsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader,
			XmlObject xmlObject, String path ) throws Exception
	{
		XmlObject[] wsdlImports = xmlObject.selectPath( path );
		for( int i = 0; i < wsdlImports.length; i++ )
		{
			String location = ( ( SimpleValue )wsdlImports[i] ).getStringValue();
			if( location != null )
			{
				if( StringUtils.hasContent( location ) )
				{
					if( !location.startsWith( "file:" ) && location.indexOf( "://" ) == -1 )
						location = Tools.joinRelativeUrl( wsdlUrl, location );

					getDefinitionParts( location, existing, loader );
				}
				else
				{
					Node domNode = ( ( Attr )wsdlImports[i].getDomNode() ).getOwnerElement();
					domNode.getParentNode().removeChild( domNode );
				}
			}
		}
	}

	/**
	 * Extracts namespaces - used in tool integrations for mapping..
	 */

	public static Collection<String> extractNamespaces( SchemaTypeSystem schemaTypes, boolean removeDefault )
	{
		Set<String> namespaces = new HashSet<String>();
		SchemaType[] globalTypes = schemaTypes.globalTypes();
		for( int c = 0; c < globalTypes.length; c++ )
		{
			namespaces.add( globalTypes[c].getName().getNamespaceURI() );
		}

		if( removeDefault )
		{
			namespaces.removeAll( defaultSchemas.keySet() );
			namespaces.remove( Constants.SOAP11_ENVELOPE_NS );
			namespaces.remove( Constants.SOAP_ENCODING_NS );
		}

		return namespaces;
	}

	/**
	 * Used when creating a TypeSystem from a complete collection of
	 * SchemaDocuments so that referenced types are not downloaded (again)
	 */

	public static void removeImports( XmlObject xmlObject ) throws XmlException
	{
		XmlObject[] imports = xmlObject.selectPath( "declare namespace s='" + Constants.XSD_NS + "' .//s:import" );

		for( int c = 0; c < imports.length; c++ )
		{
			XmlCursor cursor = imports[c].newCursor();
			cursor.removeXml();
			cursor.dispose();
		}

		XmlObject[] includes = xmlObject.selectPath( "declare namespace s='" + Constants.XSD_NS + "' .//s:include" );

		for( int c = 0; c < includes.length; c++ )
		{
			XmlCursor cursor = includes[c].newCursor();
			cursor.removeXml();
			cursor.dispose();
		}
	}

	public static boolean isInstanceOf( SchemaType schemaType, SchemaType baseType )
	{
		if( schemaType == null )
			return false;
		return schemaType.equals( baseType ) ? true : isInstanceOf( schemaType.getBaseType(), baseType );
	}

	public static boolean isBinaryType( SchemaType schemaType )
	{
		return isInstanceOf( schemaType, XmlHexBinary.type ) || isInstanceOf( schemaType, XmlBase64Binary.type );
	}

	public static String getDocumentation( SchemaType schemaType )
	{
		String result = null;
		String xsPrefix = null;

		SchemaField containerField = schemaType.getContainerField();

		if( containerField instanceof SchemaLocalElement )
		{
			SchemaAnnotation annotation = ( ( SchemaLocalElement )containerField ).getAnnotation();
			if( annotation != null )
			{
				XmlObject[] userInformation = annotation.getUserInformation();
				if( userInformation != null && userInformation.length > 0 )
				{
					XmlObject xmlObject = userInformation[0];
					XmlCursor cursor = xmlObject.newCursor();
					xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
					cursor.dispose();

					result = xmlObject.xmlText(); // XmlUtils.getElementText( (
					// Element )
					// userInformation[0].getDomNode());
				}
			}
		}

		if( result == null && schemaType != null && schemaType.getAnnotation() != null )
		{
			XmlObject[] userInformation = schemaType.getAnnotation().getUserInformation();
			if( userInformation != null && userInformation.length > 0 && userInformation[0] != null )
			{
				XmlObject xmlObject = userInformation[0];
				XmlCursor cursor = xmlObject.newCursor();
				xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
				cursor.dispose();
				result = xmlObject.xmlText(); // = XmlUtils.getElementText( (
				// Element )
				// userInformation[0].getDomNode());
			}
		}

		if( result != null )
		{
			result = result.trim();
			if( result.startsWith( "<" ) && result.endsWith( ">" ) )
			{
				int ix = result.indexOf( '>' );
				if( ix > 0 )
				{
					result = result.substring( ix + 1 );
				}

				ix = result.lastIndexOf( '<' );
				if( ix >= 0 )
				{
					result = result.substring( 0, ix );
				}
			}

			if( xsPrefix == null || xsPrefix.length() == 0 )
				xsPrefix = "xs:";
			else
				xsPrefix += ":";

			// result = result.trim().replaceAll( "<" + xsPrefix + "br/>", "\n"
			// ).trim();
			result = result.trim().replaceAll( xsPrefix, "" ).trim();

			result = StringUtils.toHtml( result );
		}

		return result;
	}

	public static String[] getEnumerationValues( SchemaType schemaType, boolean addNull )
	{
		if( schemaType != null )
		{
			XmlAnySimpleType[] enumerationValues = schemaType.getEnumerationValues();
			if( enumerationValues != null && enumerationValues.length > 0 )
			{
				if( addNull )
				{
					String[] values = new String[enumerationValues.length + 1];
					values[0] = null;

					for( int c = 1; c < values.length; c++ )
						values[c] = enumerationValues[c - 1].getStringValue();

					return values;
				}
				else
				{
					String[] values = new String[enumerationValues.length];

					for( int c = 0; c < values.length; c++ )
						values[c] = enumerationValues[c].getStringValue();

					return values;
				}
			}
		}

		return new String[0];
	}

	public static Collection<? extends QName> getExcludedTypes()
	{
		String excluded = SoapUI.getSettings().getString( WsdlSettings.EXCLUDED_TYPES, null );
		return SettingUtils.string2QNames( excluded );
	}

	public static boolean isAnyType( SchemaType schemaType )
	{
		return schemaType != null
				&& ( schemaType.getBuiltinTypeCode() == SchemaType.BTC_ANY_TYPE || ( schemaType.getBaseType() != null && schemaType
						.getBaseType().getBuiltinTypeCode() == SchemaType.BTC_ANY_TYPE ) );
	}
}
