/*
* soapUI, copyright (C) 2004-2011 eviware.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.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.xmlbeans.GDate;
import org.apache.xmlbeans.GDateBuilder;
import org.apache.xmlbeans.GDuration;
import org.apache.xmlbeans.GDurationBuilder;
import org.apache.xmlbeans.SchemaGlobalElement;
import org.apache.xmlbeans.SchemaLocalElement;
import org.apache.xmlbeans.SchemaParticle;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SimpleValue;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlDate;
import org.apache.xmlbeans.XmlDateTime;
import org.apache.xmlbeans.XmlDecimal;
import org.apache.xmlbeans.XmlDuration;
import org.apache.xmlbeans.XmlGDay;
import org.apache.xmlbeans.XmlGMonth;
import org.apache.xmlbeans.XmlGMonthDay;
import org.apache.xmlbeans.XmlGYear;
import org.apache.xmlbeans.XmlGYearMonth;
import org.apache.xmlbeans.XmlInteger;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlTime;
import org.apache.xmlbeans.impl.util.Base64;
import org.apache.xmlbeans.impl.util.HexBin;
import org.apache.xmlbeans.soap.SOAPArrayType;
import org.apache.xmlbeans.soap.SchemaWSDLArrayType;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.settings.WsdlSettings;
import com.eviware.soapui.support.StringUtils;
/**
* XmlBeans class for generating XML from XML Schemas
*/
public class SampleXmlUtil
{
private boolean _soapEnc;
private boolean _exampleContent = false;
private boolean _typeComment = false;
private Set<QName> excludedTypes = new HashSet<QName>();
private Map<QName, String[]> multiValues = null;
private boolean _skipComments;
public SampleXmlUtil( boolean soapEnc )
{
_soapEnc = soapEnc;
excludedTypes.addAll( SchemaUtils.getExcludedTypes() );
}
public boolean isSoapEnc()
{
return _soapEnc;
}
public boolean isExampleContent()
{
return _exampleContent;
}
public void setExampleContent( boolean content )
{
_exampleContent = content;
}
public boolean isTypeComment()
{
return _typeComment;
}
public void setTypeComment( boolean comment )
{
_typeComment = comment;
}
public void setMultiValues( Map<QName, String[]> multiValues )
{
this.multiValues = multiValues;
}
public String createSample( SchemaType sType )
{
XmlObject object = XmlObject.Factory.newInstance();
XmlCursor cursor = object.newCursor();
// Skip the document node
cursor.toNextToken();
// Using the type and the cursor, call the utility method to get a
// sample XML payload for that Schema element
createSampleForType( sType, cursor );
// Cursor now contains the sample payload
// Pretty print the result. Note that the cursor is positioned at the
// end of the doc so we use the original xml object that the cursor was
// created upon to do the xmlText() against.
cursor.dispose();
XmlOptions options = new XmlOptions();
options.put( XmlOptions.SAVE_PRETTY_PRINT );
options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
options.setSaveOuter();
String result = object.xmlText( options );
return result;
}
public static String createSampleForElement( SchemaGlobalElement element )
{
XmlObject xml = XmlObject.Factory.newInstance();
XmlCursor c = xml.newCursor();
c.toNextToken();
c.beginElement( element.getName() );
new SampleXmlUtil( false ).createSampleForType( element.getType(), c );
c.dispose();
XmlOptions options = new XmlOptions();
options.put( XmlOptions.SAVE_PRETTY_PRINT );
options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
options.setSaveOuter();
String result = xml.xmlText( options );
return result;
}
public static String createSampleForType( SchemaType sType )
{
XmlObject object = XmlObject.Factory.newInstance();
XmlCursor cursor = object.newCursor();
// Skip the document node
cursor.toNextToken();
// Using the type and the cursor, call the utility method to get a
// sample XML payload for that Schema element
new SampleXmlUtil( false ).createSampleForType( sType, cursor );
// Cursor now contains the sample payload
// Pretty print the result. Note that the cursor is positioned at the
// end of the doc so we use the original xml object that the cursor was
// created upon to do the xmlText() against.
cursor.dispose();
XmlOptions options = new XmlOptions();
options.put( XmlOptions.SAVE_PRETTY_PRINT );
options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
options.setSaveOuter();
String result = object.xmlText( options );
return result;
}
Random _picker = new Random( 1 );
private boolean ignoreOptional;
/**
* Cursor position Before: <theElement>^</theElement> After:
* <theElement><lots of stuff/>^</theElement>
*/
public void createSampleForType( SchemaType stype, XmlCursor xmlc )
{
_exampleContent = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_EXAMPLE_VALUE );
_typeComment = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_COMMENT_TYPE );
_skipComments = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_SKIP_COMMENTS );
QName nm = stype.getName();
if( nm == null && stype.getContainerField() != null )
nm = stype.getContainerField().getName();
if( nm != null && excludedTypes.contains( nm ) )
{
if( !_skipComments )
xmlc.insertComment( "Ignoring type [" + nm + "]" );
return;
}
if( _typeStack.contains( stype ) )
return;
_typeStack.add( stype );
try
{
if( stype.isSimpleType() || stype.isURType() )
{
processSimpleType( stype, xmlc );
return;
}
// complex Type
// <theElement>^</theElement>
processAttributes( stype, xmlc );
// <theElement attri1="string">^</theElement>
switch( stype.getContentType() )
{
case SchemaType.NOT_COMPLEX_TYPE :
case SchemaType.EMPTY_CONTENT :
// noop
break;
case SchemaType.SIMPLE_CONTENT :
{
processSimpleType( stype, xmlc );
}
break;
case SchemaType.MIXED_CONTENT :
xmlc.insertChars( pick( WORDS ) + " " );
if( stype.getContentModel() != null )
{
processParticle( stype.getContentModel(), xmlc, true );
}
xmlc.insertChars( pick( WORDS ) );
break;
case SchemaType.ELEMENT_CONTENT :
if( stype.getContentModel() != null )
{
processParticle( stype.getContentModel(), xmlc, false );
}
break;
}
}
finally
{
_typeStack.remove( _typeStack.size() - 1 );
}
}
private void processSimpleType( SchemaType stype, XmlCursor xmlc )
{
if( _soapEnc )
{
QName typeName = stype.getName();
if( typeName != null )
{
xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
}
}
String sample = sampleDataForSimpleType( stype );
xmlc.insertChars( sample );
}
private String sampleDataForSimpleType( SchemaType sType )
{
// swaRef
if( sType.getName() != null )
{
if( sType.getName().equals( new QName( "http://ws-i.org/profiles/basic/1.1/xsd", "swaRef" ) ) )
return "cid:" + ( long )( System.currentTimeMillis() * Math.random() );
// xmime base64
if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "base64Binary" ) ) )
return "cid:" + ( long )( System.currentTimeMillis() * Math.random() );
// xmime hexBinary
if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "hexBinary" ) ) )
return "cid:" + ( long )( System.currentTimeMillis() * Math.random() );
}
SchemaType primitiveType = sType.getPrimitiveType();
if( primitiveType != null
&& ( primitiveType.getBuiltinTypeCode() == SchemaType.BTC_BASE_64_BINARY || primitiveType
.getBuiltinTypeCode() == SchemaType.BTC_HEX_BINARY ) )
return "cid:" + ( long )( System.currentTimeMillis() * Math.random() );
// if( sType != null )
if( !_exampleContent )
return "?";
if( XmlObject.type.equals( sType ) )
return "anyType";
if( XmlAnySimpleType.type.equals( sType ) )
return "anySimpleType";
if( sType.getSimpleVariety() == SchemaType.LIST )
{
SchemaType itemType = sType.getListItemType();
StringBuffer sb = new StringBuffer();
int length = pickLength( sType );
if( length > 0 )
sb.append( sampleDataForSimpleType( itemType ) );
for( int i = 1; i < length; i += 1 )
{
sb.append( ' ' );
sb.append( sampleDataForSimpleType( itemType ) );
}
return sb.toString();
}
if( sType.getSimpleVariety() == SchemaType.UNION )
{
SchemaType[] possibleTypes = sType.getUnionConstituentTypes();
if( possibleTypes.length == 0 )
return "";
return sampleDataForSimpleType( possibleTypes[pick( possibleTypes.length )] );
}
XmlAnySimpleType[] enumValues = sType.getEnumerationValues();
if( enumValues != null && enumValues.length > 0 )
{
return enumValues[pick( enumValues.length )].getStringValue();
}
switch( primitiveType.getBuiltinTypeCode() )
{
default :
case SchemaType.BTC_NOT_BUILTIN :
return "";
case SchemaType.BTC_ANY_TYPE :
case SchemaType.BTC_ANY_SIMPLE :
return "anything";
case SchemaType.BTC_BOOLEAN :
return pick( 2 ) == 0 ? "true" : "false";
case SchemaType.BTC_BASE_64_BINARY :
{
String result = null;
try
{
result = new String( Base64.encode( formatToLength( pick( WORDS ), sType ).getBytes( "utf-8" ) ) );
}
catch( java.io.UnsupportedEncodingException e )
{
}
return result;
}
case SchemaType.BTC_HEX_BINARY :
return HexBin.encode( formatToLength( pick( WORDS ), sType ) );
case SchemaType.BTC_ANY_URI :
return formatToLength( "http://www." + pick( DNS1 ) + "." + pick( DNS2 ) + "/" + pick( WORDS ) + "/"
+ pick( WORDS ), sType );
case SchemaType.BTC_QNAME :
return formatToLength( "qname", sType );
case SchemaType.BTC_NOTATION :
return formatToLength( "notation", sType );
case SchemaType.BTC_FLOAT :
return "1.5E2";
case SchemaType.BTC_DOUBLE :
return "1.051732E7";
case SchemaType.BTC_DECIMAL :
switch( closestBuiltin( sType ).getBuiltinTypeCode() )
{
case SchemaType.BTC_SHORT :
return formatDecimal( "1", sType );
case SchemaType.BTC_UNSIGNED_SHORT :
return formatDecimal( "5", sType );
case SchemaType.BTC_BYTE :
return formatDecimal( "2", sType );
case SchemaType.BTC_UNSIGNED_BYTE :
return formatDecimal( "6", sType );
case SchemaType.BTC_INT :
return formatDecimal( "3", sType );
case SchemaType.BTC_UNSIGNED_INT :
return formatDecimal( "7", sType );
case SchemaType.BTC_LONG :
return formatDecimal( "10", sType );
case SchemaType.BTC_UNSIGNED_LONG :
return formatDecimal( "11", sType );
case SchemaType.BTC_INTEGER :
return formatDecimal( "100", sType );
case SchemaType.BTC_NON_POSITIVE_INTEGER :
return formatDecimal( "-200", sType );
case SchemaType.BTC_NEGATIVE_INTEGER :
return formatDecimal( "-201", sType );
case SchemaType.BTC_NON_NEGATIVE_INTEGER :
return formatDecimal( "200", sType );
case SchemaType.BTC_POSITIVE_INTEGER :
return formatDecimal( "201", sType );
default :
case SchemaType.BTC_DECIMAL :
return formatDecimal( "1000.00", sType );
}
case SchemaType.BTC_STRING :
{
String result;
switch( closestBuiltin( sType ).getBuiltinTypeCode() )
{
case SchemaType.BTC_STRING :
case SchemaType.BTC_NORMALIZED_STRING :
result = pick( WORDS, _picker.nextInt( 3 ) );
break;
case SchemaType.BTC_TOKEN :
result = pick( WORDS, _picker.nextInt( 3 ) );
break;
default :
result = pick( WORDS, _picker.nextInt( 3 ) );
break;
}
return formatToLength( result, sType );
}
case SchemaType.BTC_DURATION :
return formatDuration( sType );
case SchemaType.BTC_DATE_TIME :
case SchemaType.BTC_TIME :
case SchemaType.BTC_DATE :
case SchemaType.BTC_G_YEAR_MONTH :
case SchemaType.BTC_G_YEAR :
case SchemaType.BTC_G_MONTH_DAY :
case SchemaType.BTC_G_DAY :
case SchemaType.BTC_G_MONTH :
return formatDate( sType );
}
}
// a bit from the Aenid
public static final String[] WORDS = new String[] { "ipsa", "iovis", "rapidum", "iaculata", "e", "nubibus", "ignem",
"disiecitque", "rates", "evertitque", "aequora", "ventis", "illum", "exspirantem", "transfixo", "pectore",
"flammas", "turbine", "corripuit", "scopuloque", "infixit", "acuto", "ast", "ego", "quae", "divum", "incedo",
"regina", "iovisque", "et", "soror", "et", "coniunx", "una", "cum", "gente", "tot", "annos", "bella", "gero",
"et", "quisquam", "numen", "iunonis", "adorat", "praeterea", "aut", "supplex", "aris", "imponet", "honorem",
"talia", "flammato", "secum", "dea", "corde", "volutans", "nimborum", "in", "patriam", "loca", "feta",
"furentibus", "austris", "aeoliam", "venit", "hic", "vasto", "rex", "aeolus", "antro", "luctantis", "ventos",
"tempestatesque", "sonoras", "imperio", "premit", "ac", "vinclis", "et", "carcere", "frenat", "illi",
"indignantes", "magno", "cum", "murmure", "montis", "circum", "claustra", "fremunt", "celsa", "sedet",
"aeolus", "arce", "sceptra", "tenens", "mollitque", "animos", "et", "temperat", "iras", "ni", "faciat",
"maria", "ac", "terras", "caelumque", "profundum", "quippe", "ferant", "rapidi", "secum", "verrantque", "per",
"auras", "sed", "pater", "omnipotens", "speluncis", "abdidit", "atris", "hoc", "metuens", "molemque", "et",
"montis", "insuper", "altos", "imposuit", "regemque", "dedit", "qui", "foedere", "certo", "et", "premere",
"et", "laxas", "sciret", "dare", "iussus", "habenas", };
private static final String[] DNS1 = new String[] { "corp", "your", "my", "sample", "company", "test", "any" };
private static final String[] DNS2 = new String[] { "com", "org", "com", "gov", "org", "com", "org", "com", "edu" };
private int pick( int n )
{
return _picker.nextInt( n );
}
private String pick( String[] a )
{
return a[pick( a.length )];
}
private String pick( String[] a, int count )
{
if( count <= 0 )
count = 1;
// return "";
int i = pick( a.length );
StringBuffer sb = new StringBuffer( a[i] );
while( count-- > 0 )
{
i += 1;
if( i >= a.length )
i = 0;
sb.append( ' ' );
sb.append( a[i] );
}
return sb.toString();
}
@SuppressWarnings( "unused" )
private String pickDigits( int digits )
{
StringBuffer sb = new StringBuffer();
while( digits-- > 0 )
sb.append( Integer.toString( pick( 10 ) ) );
return sb.toString();
}
private int pickLength( SchemaType sType )
{
XmlInteger length = ( XmlInteger )sType.getFacet( SchemaType.FACET_LENGTH );
if( length != null )
return length.getBigIntegerValue().intValue();
XmlInteger min = ( XmlInteger )sType.getFacet( SchemaType.FACET_MIN_LENGTH );
XmlInteger max = ( XmlInteger )sType.getFacet( SchemaType.FACET_MAX_LENGTH );
int minInt, maxInt;
if( min == null )
minInt = 0;
else
minInt = min.getBigIntegerValue().intValue();
if( max == null )
maxInt = Integer.MAX_VALUE;
else
maxInt = max.getBigIntegerValue().intValue();
// We try to keep the length of the array within reasonable limits,
// at least 1 item and at most 3 if possible
if( minInt == 0 && maxInt >= 1 )
minInt = 1;
if( maxInt > minInt + 2 )
maxInt = minInt + 2;
if( maxInt < minInt )
maxInt = minInt;
return minInt + pick( maxInt - minInt );
}
/**
* Formats a given string to the required length, using the following
* operations: - append the source string to itself as necessary to pass the
* minLength; - truncate the result of previous step, if necessary, to keep
* it within minLength.
*/
private String formatToLength( String s, SchemaType sType )
{
String result = s;
try
{
SimpleValue min = ( SimpleValue )sType.getFacet( SchemaType.FACET_LENGTH );
if( min == null )
min = ( SimpleValue )sType.getFacet( SchemaType.FACET_MIN_LENGTH );
if( min != null )
{
int len = min.getIntValue();
while( result.length() < len )
result = result + result;
}
SimpleValue max = ( SimpleValue )sType.getFacet( SchemaType.FACET_LENGTH );
if( max == null )
max = ( SimpleValue )sType.getFacet( SchemaType.FACET_MAX_LENGTH );
if( max != null )
{
int len = max.getIntValue();
if( result.length() > len )
result = result.substring( 0, len );
}
}
catch( Exception e ) // intValue can be out of range
{
}
return result;
}
private String formatDecimal( String start, SchemaType sType )
{
BigDecimal result = new BigDecimal( start );
XmlDecimal xmlD;
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
BigDecimal min = xmlD != null ? xmlD.getBigDecimalValue() : null;
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
BigDecimal max = xmlD != null ? xmlD.getBigDecimalValue() : null;
boolean minInclusive = true, maxInclusive = true;
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( xmlD != null )
{
BigDecimal minExcl = xmlD.getBigDecimalValue();
if( min == null || min.compareTo( minExcl ) < 0 )
{
min = minExcl;
minInclusive = false;
}
}
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( xmlD != null )
{
BigDecimal maxExcl = xmlD.getBigDecimalValue();
if( max == null || max.compareTo( maxExcl ) > 0 )
{
max = maxExcl;
maxInclusive = false;
}
}
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_TOTAL_DIGITS );
int totalDigits = -1;
if( xmlD != null )
{
totalDigits = xmlD.getBigDecimalValue().intValue();
StringBuffer sb = new StringBuffer( totalDigits );
for( int i = 0; i < totalDigits; i++ )
sb.append( '9' );
BigDecimal digitsLimit = new BigDecimal( sb.toString() );
if( max != null && max.compareTo( digitsLimit ) > 0 )
{
max = digitsLimit;
maxInclusive = true;
}
digitsLimit = digitsLimit.negate();
if( min != null && min.compareTo( digitsLimit ) < 0 )
{
min = digitsLimit;
minInclusive = true;
}
}
int sigMin = min == null ? 1 : result.compareTo( min );
int sigMax = max == null ? -1 : result.compareTo( max );
boolean minOk = sigMin > 0 || sigMin == 0 && minInclusive;
boolean maxOk = sigMax < 0 || sigMax == 0 && maxInclusive;
// Compute the minimum increment
xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_FRACTION_DIGITS );
int fractionDigits = -1;
BigDecimal increment;
if( xmlD == null )
increment = new BigDecimal( 1 );
else
{
fractionDigits = xmlD.getBigDecimalValue().intValue();
if( fractionDigits > 0 )
{
StringBuffer sb = new StringBuffer( "0." );
for( int i = 1; i < fractionDigits; i++ )
sb.append( '0' );
sb.append( '1' );
increment = new BigDecimal( sb.toString() );
}
else
increment = new BigDecimal( 1 );
}
if( minOk && maxOk )
{
// OK
}
else if( minOk && !maxOk )
{
// TOO BIG
if( maxInclusive )
result = max;
else
result = max.subtract( increment );
}
else if( !minOk && maxOk )
{
// TOO SMALL
if( minInclusive )
result = min;
else
result = min.add( increment );
}
else
{
// MIN > MAX!!
}
// We have the number
// Adjust the scale according to the totalDigits and fractionDigits
int digits = 0;
BigDecimal ONE = new BigDecimal( BigInteger.ONE );
for( BigDecimal n = result; n.abs().compareTo( ONE ) >= 0; digits++ )
n = n.movePointLeft( 1 );
if( fractionDigits > 0 )
if( totalDigits >= 0 )
result.setScale( Math.max( fractionDigits, totalDigits - digits ) );
else
result.setScale( fractionDigits );
else if( fractionDigits == 0 )
result.setScale( 0 );
return result.toString();
}
private String formatDuration( SchemaType sType )
{
XmlDuration d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
GDuration minInclusive = null;
if( d != null )
minInclusive = d.getGDurationValue();
d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
GDuration maxInclusive = null;
if( d != null )
maxInclusive = d.getGDurationValue();
d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
GDuration minExclusive = null;
if( d != null )
minExclusive = d.getGDurationValue();
d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
GDuration maxExclusive = null;
if( d != null )
maxExclusive = d.getGDurationValue();
GDurationBuilder gdurb = new GDurationBuilder();
@SuppressWarnings( "unused" )
BigInteger min, max;
gdurb.setSecond( pick( 800000 ) );
gdurb.setMonth( pick( 20 ) );
// Years
// Months
// Days
// Hours
// Minutes
// Seconds
// Fractions
if( minInclusive != null )
{
if( gdurb.getYear() < minInclusive.getYear() )
gdurb.setYear( minInclusive.getYear() );
if( gdurb.getMonth() < minInclusive.getMonth() )
gdurb.setMonth( minInclusive.getMonth() );
if( gdurb.getDay() < minInclusive.getDay() )
gdurb.setDay( minInclusive.getDay() );
if( gdurb.getHour() < minInclusive.getHour() )
gdurb.setHour( minInclusive.getHour() );
if( gdurb.getMinute() < minInclusive.getMinute() )
gdurb.setMinute( minInclusive.getMinute() );
if( gdurb.getSecond() < minInclusive.getSecond() )
gdurb.setSecond( minInclusive.getSecond() );
if( gdurb.getFraction().compareTo( minInclusive.getFraction() ) < 0 )
gdurb.setFraction( minInclusive.getFraction() );
}
if( maxInclusive != null )
{
if( gdurb.getYear() > maxInclusive.getYear() )
gdurb.setYear( maxInclusive.getYear() );
if( gdurb.getMonth() > maxInclusive.getMonth() )
gdurb.setMonth( maxInclusive.getMonth() );
if( gdurb.getDay() > maxInclusive.getDay() )
gdurb.setDay( maxInclusive.getDay() );
if( gdurb.getHour() > maxInclusive.getHour() )
gdurb.setHour( maxInclusive.getHour() );
if( gdurb.getMinute() > maxInclusive.getMinute() )
gdurb.setMinute( maxInclusive.getMinute() );
if( gdurb.getSecond() > maxInclusive.getSecond() )
gdurb.setSecond( maxInclusive.getSecond() );
if( gdurb.getFraction().compareTo( maxInclusive.getFraction() ) > 0 )
gdurb.setFraction( maxInclusive.getFraction() );
}
if( minExclusive != null )
{
if( gdurb.getYear() <= minExclusive.getYear() )
gdurb.setYear( minExclusive.getYear() + 1 );
if( gdurb.getMonth() <= minExclusive.getMonth() )
gdurb.setMonth( minExclusive.getMonth() + 1 );
if( gdurb.getDay() <= minExclusive.getDay() )
gdurb.setDay( minExclusive.getDay() + 1 );
if( gdurb.getHour() <= minExclusive.getHour() )
gdurb.setHour( minExclusive.getHour() + 1 );
if( gdurb.getMinute() <= minExclusive.getMinute() )
gdurb.setMinute( minExclusive.getMinute() + 1 );
if( gdurb.getSecond() <= minExclusive.getSecond() )
gdurb.setSecond( minExclusive.getSecond() + 1 );
if( gdurb.getFraction().compareTo( minExclusive.getFraction() ) <= 0 )
gdurb.setFraction( minExclusive.getFraction().add( new BigDecimal( 0.001 ) ) );
}
if( maxExclusive != null )
{
if( gdurb.getYear() > maxExclusive.getYear() )
gdurb.setYear( maxExclusive.getYear() );
if( gdurb.getMonth() > maxExclusive.getMonth() )
gdurb.setMonth( maxExclusive.getMonth() );
if( gdurb.getDay() > maxExclusive.getDay() )
gdurb.setDay( maxExclusive.getDay() );
if( gdurb.getHour() > maxExclusive.getHour() )
gdurb.setHour( maxExclusive.getHour() );
if( gdurb.getMinute() > maxExclusive.getMinute() )
gdurb.setMinute( maxExclusive.getMinute() );
if( gdurb.getSecond() > maxExclusive.getSecond() )
gdurb.setSecond( maxExclusive.getSecond() );
if( gdurb.getFraction().compareTo( maxExclusive.getFraction() ) > 0 )
gdurb.setFraction( maxExclusive.getFraction() );
}
gdurb.normalize();
return gdurb.toString();
}
private String formatDate( SchemaType sType )
{
GDateBuilder gdateb = new GDateBuilder( new Date( 1000L * pick( 365 * 24 * 60 * 60 ) + ( 30L + pick( 20 ) ) * 365
* 24 * 60 * 60 * 1000 ) );
GDate min = null, max = null;
// Find the min and the max according to the type
switch( sType.getPrimitiveType().getBuiltinTypeCode() )
{
case SchemaType.BTC_DATE_TIME :
{
XmlDateTime x = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_TIME :
{
XmlTime x = ( XmlTime )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlTime )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlTime )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlTime )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_DATE :
{
XmlDate x = ( XmlDate )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlDate )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlDate )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlDate )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_G_YEAR_MONTH :
{
XmlGYearMonth x = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_G_YEAR :
{
XmlGYear x = ( XmlGYear )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlGYear )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlGYear )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlGYear )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_G_MONTH_DAY :
{
XmlGMonthDay x = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_G_DAY :
{
XmlGDay x = ( XmlGDay )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlGDay )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlGDay )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlGDay )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
case SchemaType.BTC_G_MONTH :
{
XmlGMonth x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
if( x != null )
min = x.getGDateValue();
x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
if( x != null )
if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
min = x.getGDateValue();
x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
if( x != null )
max = x.getGDateValue();
x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
if( x != null )
if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
max = x.getGDateValue();
break;
}
}
if( min != null && max == null )
{
if( min.compareToGDate( gdateb ) >= 0 )
{
// Reset the date to min + (1-8) hours
Calendar c = gdateb.getCalendar();
c.add( Calendar.HOUR_OF_DAY, pick( 8 ) );
gdateb = new GDateBuilder( c );
}
}
else if( min == null && max != null )
{
if( max.compareToGDate( gdateb ) <= 0 )
{
// Reset the date to max - (1-8) hours
Calendar c = gdateb.getCalendar();
c.add( Calendar.HOUR_OF_DAY, 0 - pick( 8 ) );
gdateb = new GDateBuilder( c );
}
}
else if( min != null && max != null )
{
if( min.compareToGDate( gdateb ) >= 0 || max.compareToGDate( gdateb ) <= 0 )
{
// Find a date between the two
Calendar c = min.getCalendar();
Calendar cmax = max.getCalendar();
c.add( Calendar.HOUR_OF_DAY, 1 );
if( c.after( cmax ) )
{
c.add( Calendar.HOUR_OF_DAY, -1 );
c.add( Calendar.MINUTE, 1 );
if( c.after( cmax ) )
{
c.add( Calendar.MINUTE, -1 );
c.add( Calendar.SECOND, 1 );
if( c.after( cmax ) )
{
c.add( Calendar.SECOND, -1 );
c.add( Calendar.MILLISECOND, 1 );
if( c.after( cmax ) )
c.add( Calendar.MILLISECOND, -1 );
}
}
}
gdateb = new GDateBuilder( c );
}
}
gdateb.setBuiltinTypeCode( sType.getPrimitiveType().getBuiltinTypeCode() );
if( pick( 2 ) == 0 )
gdateb.clearTimeZone();
return gdateb.toString();
}
private SchemaType closestBuiltin( SchemaType sType )
{
while( !sType.isBuiltinType() )
sType = sType.getBaseType();
return sType;
}
/**
* Cracks a combined QName of the form URL:localname
*/
public static QName crackQName( String qName )
{
String ns;
String name;
int index = qName.lastIndexOf( ':' );
if( index >= 0 )
{
ns = qName.substring( 0, index );
name = qName.substring( index + 1 );
}
else
{
ns = "";
name = qName;
}
return new QName( ns, name );
}
/**
* Cursor position: Before this call: <outer><foo/>^</outer> (cursor at the
* ^) After this call: <<outer><foo/><bar/>som text<etc/>^</outer>
*/
private void processParticle( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
int loop = determineMinMaxForSample( sp, xmlc );
while( loop-- > 0 )
{
switch( sp.getParticleType() )
{
case ( SchemaParticle.ELEMENT ) :
processElement( sp, xmlc, mixed );
break;
case ( SchemaParticle.SEQUENCE ) :
processSequence( sp, xmlc, mixed );
break;
case ( SchemaParticle.CHOICE ) :
processChoice( sp, xmlc, mixed );
break;
case ( SchemaParticle.ALL ) :
processAll( sp, xmlc, mixed );
break;
case ( SchemaParticle.WILDCARD ) :
processWildCard( sp, xmlc, mixed );
break;
default :
// throw new Exception("No Match on Schema Particle Type: " +
// String.valueOf(sp.getParticleType()));
}
}
}
private int determineMinMaxForSample( SchemaParticle sp, XmlCursor xmlc )
{
int minOccurs = sp.getIntMinOccurs();
int maxOccurs = sp.getIntMaxOccurs();
if( minOccurs == maxOccurs )
return minOccurs;
if( minOccurs == 0 && ignoreOptional )
return 0;
int result = minOccurs;
if( result == 0 )
result = 1;
if( sp.getParticleType() != SchemaParticle.ELEMENT )
return result;
// it probably only makes sense to put comments in front of individual
// elements that repeat
if( !_skipComments )
{
if( sp.getMaxOccurs() == null )
{
// xmlc.insertComment("The next " + getItemNameOrType(sp, xmlc) + "
// may
// be repeated " + minOccurs + " or more times");
if( minOccurs == 0 )
xmlc.insertComment( "Zero or more repetitions:" );
else
xmlc.insertComment( minOccurs + " or more repetitions:" );
}
else if( sp.getIntMaxOccurs() > 1 )
{
xmlc.insertComment( minOccurs + " to " + String.valueOf( sp.getMaxOccurs() ) + " repetitions:" );
}
else
{
xmlc.insertComment( "Optional:" );
}
}
return result;
}
/*
* Return a name for the element or the particle type to use in the comment
* for minoccurs, max occurs
*/
@SuppressWarnings( "unused" )
private String getItemNameOrType( SchemaParticle sp, XmlCursor xmlc )
{
String elementOrTypeName = null;
if( sp.getParticleType() == SchemaParticle.ELEMENT )
{
elementOrTypeName = "Element (" + sp.getName().getLocalPart() + ")";
}
else
{
elementOrTypeName = printParticleType( sp.getParticleType() );
}
return elementOrTypeName;
}
private void processElement( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
// cast as schema local element
SchemaLocalElement element = ( SchemaLocalElement )sp;
// Add comment about type
addElementTypeAndRestricionsComment( element, xmlc );
// / ^ -> <elemenname></elem>^
if( _soapEnc )
xmlc.insertElement( element.getName().getLocalPart() ); // soap
// encoded?
// drop
// namespaces.
else
xmlc.insertElement( element.getName().getLocalPart(), element.getName().getNamespaceURI() );
// / -> <elem>^</elem>
// processAttributes( sp.getType(), xmlc );
xmlc.toPrevToken();
// -> <elem>stuff^</elem>
String[] values = null;
if( multiValues != null )
values = multiValues.get( element.getName() );
if( values != null )
xmlc.insertChars( StringUtils.join( values, "," ) );
else if( sp.isDefault() )
xmlc.insertChars( sp.getDefaultText() );
else
createSampleForType( element.getType(), xmlc );
// -> <elem>stuff</elem>^
xmlc.toNextToken();
}
@SuppressWarnings( "unused" )
private void moveToken( int numToMove, XmlCursor xmlc )
{
for( int i = 0; i < Math.abs( numToMove ); i++ )
{
if( numToMove < 0 )
{
xmlc.toPrevToken();
}
else
{
xmlc.toNextToken();
}
}
}
private static final String formatQName( XmlCursor xmlc, QName qName )
{
XmlCursor parent = xmlc.newCursor();
parent.toParent();
String prefix = parent.prefixForNamespace( qName.getNamespaceURI() );
parent.dispose();
String name;
if( prefix == null || prefix.length() == 0 )
name = qName.getLocalPart();
else
name = prefix + ":" + qName.getLocalPart();
return name;
}
private static final QName HREF = new QName( "href" );
private static final QName ID = new QName( "id" );
public static final QName XSI_TYPE = new QName( "http://www.w3.org/2001/XMLSchema-instance", "type" );
public static final QName ENC_ARRAYTYPE = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "arrayType" );
private static final QName ENC_OFFSET = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "offset" );
public static final Set<QName> SKIPPED_SOAP_ATTRS = new HashSet<QName>( Arrays.asList( new QName[] { HREF, ID,
ENC_OFFSET } ) );
private void processAttributes( SchemaType stype, XmlCursor xmlc )
{
if( _soapEnc )
{
QName typeName = stype.getName();
if( typeName != null )
{
xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
}
}
SchemaProperty[] attrProps = stype.getAttributeProperties();
for( int i = 0; i < attrProps.length; i++ )
{
SchemaProperty attr = attrProps[i];
if( attr.getMinOccurs().intValue() == 0 && ignoreOptional )
continue;
if( attr.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "contentType" ) ) )
{
xmlc.insertAttributeWithValue( attr.getName(), "application/?" );
continue;
}
if( _soapEnc )
{
if( SKIPPED_SOAP_ATTRS.contains( attr.getName() ) )
continue;
if( ENC_ARRAYTYPE.equals( attr.getName() ) )
{
SOAPArrayType arrayType = ( ( SchemaWSDLArrayType )stype.getAttributeModel().getAttribute(
attr.getName() ) ).getWSDLArrayType();
if( arrayType != null )
xmlc.insertAttributeWithValue( attr.getName(),
formatQName( xmlc, arrayType.getQName() ) + arrayType.soap11DimensionString() );
continue;
}
}
String value = null;
if( multiValues != null )
{
String[] values = multiValues.get( attr.getName() );
if( values != null )
value = StringUtils.join( values, "," );
}
if( value == null )
value = attr.getDefaultText();
if( value == null )
value = sampleDataForSimpleType( attr.getType() );
xmlc.insertAttributeWithValue( attr.getName(), value );
}
}
private void processSequence( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
SchemaParticle[] spc = sp.getParticleChildren();
for( int i = 0; i < spc.length; i++ )
{
// / <parent>maybestuff^</parent>
processParticle( spc[i], xmlc, mixed );
// <parent>maybestuff...morestuff^</parent>
if( mixed && i < spc.length - 1 )
xmlc.insertChars( pick( WORDS ) );
}
}
private void processChoice( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
SchemaParticle[] spc = sp.getParticleChildren();
if( !_skipComments )
xmlc.insertComment( "You have a CHOICE of the next " + String.valueOf( spc.length ) + " items at this level" );
for( int i = 0; i < spc.length; i++ )
{
processParticle( spc[i], xmlc, mixed );
}
}
private void processAll( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
SchemaParticle[] spc = sp.getParticleChildren();
if( !_skipComments )
xmlc.insertComment( "You may enter the following " + String.valueOf( spc.length ) + " items in any order" );
for( int i = 0; i < spc.length; i++ )
{
processParticle( spc[i], xmlc, mixed );
if( mixed && i < spc.length - 1 )
xmlc.insertChars( pick( WORDS ) );
}
}
private void processWildCard( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
{
if( !_skipComments )
xmlc.insertComment( "You may enter ANY elements at this point" );
// xmlc.insertElement("AnyElement");
}
/**
* This method will get the base type for the schema type
*/
@SuppressWarnings( "unused" )
private static QName getClosestName( SchemaType sType )
{
while( sType.getName() == null )
sType = sType.getBaseType();
return sType.getName();
}
private String printParticleType( int particleType )
{
StringBuffer returnParticleType = new StringBuffer();
returnParticleType.append( "Schema Particle Type: " );
switch( particleType )
{
case SchemaParticle.ALL :
returnParticleType.append( "ALL\n" );
break;
case SchemaParticle.CHOICE :
returnParticleType.append( "CHOICE\n" );
break;
case SchemaParticle.ELEMENT :
returnParticleType.append( "ELEMENT\n" );
break;
case SchemaParticle.SEQUENCE :
returnParticleType.append( "SEQUENCE\n" );
break;
case SchemaParticle.WILDCARD :
returnParticleType.append( "WILDCARD\n" );
break;
default :
returnParticleType.append( "Schema Particle Type Unknown" );
break;
}
return returnParticleType.toString();
}
private ArrayList<SchemaType> _typeStack = new ArrayList<SchemaType>();
public boolean isIgnoreOptional()
{
return ignoreOptional;
}
public void setIgnoreOptional( boolean ignoreOptional )
{
this.ignoreOptional = ignoreOptional;
}
private void addElementTypeAndRestricionsComment( SchemaLocalElement element, XmlCursor xmlc )
{
SchemaType type = element.getType();
if( _typeComment && ( type != null && type.isSimpleType() ) )
{
String info = "";
XmlAnySimpleType[] values = type.getEnumerationValues();
if( values != null && values.length > 0 )
{
info = " - enumeration: [";
for( int c = 0; c < values.length; c++ )
{
if( c > 0 )
info += ",";
info += values[c].getStringValue();
}
info += "]";
}
if( type.isAnonymousType() )
xmlc.insertComment( "anonymous type" + info );
else
xmlc.insertComment( "type: " + type.getName().getLocalPart() + info );
}
}
}