1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wadl.inference.support;
14
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 import org.apache.xmlbeans.XmlAnySimpleType;
21 import org.apache.xmlbeans.XmlBase64Binary;
22 import org.apache.xmlbeans.XmlBoolean;
23 import org.apache.xmlbeans.XmlDate;
24 import org.apache.xmlbeans.XmlDateTime;
25 import org.apache.xmlbeans.XmlDecimal;
26 import org.apache.xmlbeans.XmlGDay;
27 import org.apache.xmlbeans.XmlGMonth;
28 import org.apache.xmlbeans.XmlGYear;
29 import org.apache.xmlbeans.XmlGYearMonth;
30 import org.apache.xmlbeans.XmlHexBinary;
31 import org.apache.xmlbeans.XmlInteger;
32 import org.apache.xmlbeans.XmlNegativeInteger;
33 import org.apache.xmlbeans.XmlNonNegativeInteger;
34 import org.apache.xmlbeans.XmlNonPositiveInteger;
35 import org.apache.xmlbeans.XmlPositiveInteger;
36 import org.apache.xmlbeans.XmlString;
37 import org.apache.xmlbeans.XmlTime;
38
39 /***
40 * XML Schema inferred from gathered XML data.
41 *
42 * @author Dain Nilsson
43 */
44 public class TypeInferrer
45 {
46 private static TypeInferrer ref;
47 private TypeTree types;
48 private Map<XmlAnySimpleType, TypeTree> typeTable;
49
50 /***
51 * Get the instance of the XmlAnySimpleType with the type xs:<typeName>.
52 *
53 * @param typeName
54 * @return Returns the XmlAnySimpleType, if available. Otherwise returns
55 * null.
56 */
57 public static XmlAnySimpleType getType( String typeName )
58 {
59 for( XmlAnySimpleType item : getRef().typeTable.keySet() )
60 if( item.schemaType().getName().getLocalPart().equals( typeName ) )
61 return item;
62 return null;
63 }
64
65 /***
66 * Get the XmlAnySimpleType that describes a simple value that is empty.
67 *
68 * @return Returns the xs:string XmlAnySimpleType.
69 */
70 public static XmlAnySimpleType getBlankType()
71 {
72 return getRef().types.type;
73 }
74
75 /***
76 * Given a value and a type, a new type will be returned that validates
77 * values for both the given type, and the new value.
78 *
79 * @param value
80 * The new value to expand the type for.
81 * @param baseType
82 * The type to be expanded.
83 * @return The new expanded type.
84 */
85 public static XmlAnySimpleType expandTypeForValue( String value, XmlAnySimpleType baseType )
86 {
87 return getRef().expandTypeForValueInternal( baseType, value );
88 }
89
90 /***
91 * Given a simple value, infers the type of the value.
92 *
93 * @param value
94 * The value to assign a type to.
95 * @return Returns the inferred type for the given value.
96 */
97 public static XmlAnySimpleType inferSimpleType( String value )
98 {
99 return getRef().inferSimpleTypeRec( value, getRef().types );
100 }
101
102 /***
103 * Validates a string against an XmlAnySimpleType.
104 *
105 * @param value
106 * The value to validate.
107 * @param type
108 * The XmlAnySimpleType to validate against.
109 * @return True if the value validates, false if not.
110 */
111 public static boolean validateSimpleType( String value, XmlAnySimpleType type )
112 {
113 try
114 {
115 type.setStringValue( value );
116 return type.validate();
117 }
118 catch( Exception e )
119 {
120 return false;
121 }
122 }
123
124 private static TypeInferrer getRef()
125 {
126 if( ref == null )
127 ref = new TypeInferrer();
128 return ref;
129 }
130
131 private TypeInferrer()
132 {
133 typeTable = new HashMap<XmlAnySimpleType, TypeTree>();
134 TypeTree xmlbool = new TypeTree( XmlBoolean.Factory.newInstance() );
135 typeTable.put( xmlbool.type, xmlbool );
136 TypeTree xmlbool2 = new TypeTree( XmlBoolean.Factory.newInstance() );
137 typeTable.put( xmlbool2.type, xmlbool2 );
138 TypeTree xmlnegint = new TypeTree( XmlNegativeInteger.Factory.newInstance() );
139 typeTable.put( xmlnegint.type, xmlnegint );
140 TypeTree xmlposint = new TypeTree( XmlPositiveInteger.Factory.newInstance() );
141 typeTable.put( xmlposint.type, xmlposint );
142 TypeTree xmlnonnegint = new TypeTree( XmlNonNegativeInteger.Factory.newInstance() );
143 typeTable.put( xmlnonnegint.type, xmlnonnegint );
144 xmlnonnegint.addChild( xmlposint );
145 xmlnonnegint.addChild( xmlbool );
146 TypeTree xmlnonposint = new TypeTree( XmlNonPositiveInteger.Factory.newInstance() );
147 typeTable.put( xmlnonposint.type, xmlnonposint );
148 xmlnonposint.addChild( xmlnegint );
149 TypeTree xmlint = new TypeTree( XmlInteger.Factory.newInstance() );
150 typeTable.put( xmlint.type, xmlint );
151 xmlint.addChild( xmlnonnegint );
152 xmlint.addChild( xmlnonposint );
153 TypeTree xmldec = new TypeTree( XmlDecimal.Factory.newInstance() );
154 typeTable.put( xmldec.type, xmldec );
155 xmldec.addChild( xmlint );
156 TypeTree xmldate = new TypeTree( XmlDate.Factory.newInstance() );
157 typeTable.put( xmldate.type, xmldate );
158 TypeTree xmltime = new TypeTree( XmlTime.Factory.newInstance() );
159 typeTable.put( xmltime.type, xmltime );
160 TypeTree xmldatetime = new TypeTree( XmlDateTime.Factory.newInstance() );
161 typeTable.put( xmldatetime.type, xmldatetime );
162 TypeTree xmlhexbin = new TypeTree( XmlHexBinary.Factory.newInstance() );
163 typeTable.put( xmlhexbin.type, xmlhexbin );
164 TypeTree xmlb64bin = new TypeTree( XmlBase64Binary.Factory.newInstance() );
165 typeTable.put( xmlb64bin.type, xmlb64bin );
166 TypeTree xmlgyearmonth = new TypeTree( XmlGYearMonth.Factory.newInstance() );
167 typeTable.put( xmlgyearmonth.type, xmlgyearmonth );
168 TypeTree xmlgyear = new TypeTree( XmlGYear.Factory.newInstance() );
169 typeTable.put( xmlgyear.type, xmlgyear );
170 TypeTree xmlgmonth = new TypeTree( XmlGMonth.Factory.newInstance() );
171 typeTable.put( xmlgmonth.type, xmlgmonth );
172 TypeTree xmlgday = new TypeTree( XmlGDay.Factory.newInstance() );
173 typeTable.put( xmlgday.type, xmlgday );
174 TypeTree xmlstring = new TypeTree( XmlString.Factory.newInstance() );
175 typeTable.put( xmlstring.type, xmlstring );
176 xmlstring.addChild( xmldec );
177 xmlstring.addChild( xmldate );
178 xmlstring.addChild( xmltime );
179 xmlstring.addChild( xmldatetime );
180 xmlstring.addChild( xmlbool2 );
181 xmlstring.addChild( xmlgyearmonth );
182 xmlstring.addChild( xmlgyear );
183 xmlstring.addChild( xmlgmonth );
184 xmlstring.addChild( xmlgday );
185 xmlstring.addChild( xmlhexbin );
186
187 types = xmlstring;
188 }
189
190 private XmlAnySimpleType expandTypeForValueInternal( XmlAnySimpleType type, String value )
191 {
192 TypeTree p = typeTable.get( type );
193 while( !validateSimpleType( value, p.type ) )
194 {
195 p = p.parent;
196 }
197 return p.type;
198 }
199
200 private XmlAnySimpleType inferSimpleTypeRec( String value, TypeTree p )
201 {
202 for( TypeTree item : p.children )
203 if( validateSimpleType( value, item.type ) )
204 return inferSimpleTypeRec( value, item );
205 return p.type;
206 }
207
208 private class TypeTree
209 {
210 public XmlAnySimpleType type;
211 public TypeTree parent;
212 public List<TypeTree> children;
213
214 public TypeTree( XmlAnySimpleType type )
215 {
216 this.type = type;
217 children = new ArrayList<TypeTree>();
218 }
219
220 public void addChild( TypeTree type )
221 {
222 children.add( type );
223 type.parent = this;
224 }
225 }
226
227 }